fix: 防止价格获取并发竞态条件
问题:多个并发请求同时获取同一股票价格,导致: 1. 外部 API 被重复调用(可能被限流) 2. 部分请求失败导致收益率显示 0% 解决方案: - 使用 ConcurrentDictionary 存储进行中的请求 - GetOrAdd 模式确保同一时间只有一个请求在获取价格 - 其他并发请求等待第一个请求的结果 - 请求完成后移除 pending 任务
This commit is contained in:
parent
0579e2f47a
commit
3768f6e747
@ -2,6 +2,7 @@ using AssetManager.Data;
|
||||
using AssetManager.Data.Repositories;
|
||||
using AssetManager.Models.DTOs;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace AssetManager.Infrastructure.Services;
|
||||
|
||||
@ -20,6 +21,9 @@ public class MarketDataService : IMarketDataService
|
||||
private readonly ITiingoMarketService _tiingoService;
|
||||
private readonly IOkxMarketService _okxService;
|
||||
private readonly IMarketDataRepository _marketDataRepo;
|
||||
|
||||
// 防止并发请求同一股票
|
||||
private readonly ConcurrentDictionary<string, Task<MarketPriceResponse>> _pendingPriceRequests = new();
|
||||
|
||||
public MarketDataService(
|
||||
ILogger<MarketDataService> logger,
|
||||
@ -39,9 +43,11 @@ public class MarketDataService : IMarketDataService
|
||||
|
||||
/// <summary>
|
||||
/// 获取实时价格(自动根据资产类型路由到对应数据源)
|
||||
/// 使用并发控制防止重复请求
|
||||
/// </summary>
|
||||
public async Task<MarketPriceResponse> GetPriceAsync(string symbol, string assetType)
|
||||
{
|
||||
var cacheKey = $"{symbol.ToUpper()}_{assetType.ToUpper()}";
|
||||
_logger.LogInformation("获取实时价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType);
|
||||
|
||||
// 先查缓存
|
||||
@ -60,7 +66,27 @@ public class MarketDataService : IMarketDataService
|
||||
};
|
||||
}
|
||||
|
||||
// 缓存未命中,调用API
|
||||
// 使用 GetOrAdd 模式防止并发重复请求
|
||||
var priceTask = _pendingPriceRequests.GetOrAdd(cacheKey, _ => FetchPriceFromSourceAsync(symbol, assetType));
|
||||
|
||||
try
|
||||
{
|
||||
return await priceTask;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 请求完成后移除(无论成功失败)
|
||||
_pendingPriceRequests.TryRemove(cacheKey, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从数据源获取价格(内部方法)
|
||||
/// </summary>
|
||||
private async Task<MarketPriceResponse> FetchPriceFromSourceAsync(string symbol, string assetType)
|
||||
{
|
||||
_logger.LogInformation("从数据源获取价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType);
|
||||
|
||||
MarketPriceResponse response;
|
||||
string source;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user