fix: 增强价格获取稳定性和日志追踪
问题排查: 1. 缓存命中时验证价格有效性(Price > 0) 2. 外部 API 返回无效价格时拒绝写入缓存 3. 缓存查询层添加详细日志 4. 捕获缓存查询异常并返回 null 改进: - 缓存价格 <= 0 时忽略缓存重新获取 - 外部 API 价格 <= 0 时抛出异常,避免污染缓存 - 详细日志追踪价格获取全流程
This commit is contained in:
parent
3768f6e747
commit
3fb2403e85
@ -25,9 +25,30 @@ public class MarketDataRepository : IMarketDataRepository
|
||||
public async Task<MarketPriceCache?> GetPriceCacheAsync(string symbol, string assetType)
|
||||
{
|
||||
var cacheKey = GenerateCacheKey(symbol, assetType);
|
||||
return await _db.Queryable<MarketPriceCache>()
|
||||
.Where(p => p.Id == cacheKey && p.ExpiredAt > DateTime.Now)
|
||||
.FirstAsync();
|
||||
_logger.LogDebug("[缓存查询] CacheKey={CacheKey}, Symbol={Symbol}, AssetType={AssetType}", cacheKey, symbol, assetType);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _db.Queryable<MarketPriceCache>()
|
||||
.Where(p => p.Id == cacheKey && p.ExpiredAt > DateTime.Now)
|
||||
.FirstAsync();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
_logger.LogDebug("[缓存查询成功] CacheKey={CacheKey}, Price={Price}, ExpiredAt={ExpiredAt}", cacheKey, result.Price, result.ExpiredAt);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug("[缓存查询无结果] CacheKey={CacheKey}", cacheKey);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "[缓存查询异常] CacheKey={CacheKey}", cacheKey);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> SavePriceCacheAsync(MarketPriceCache cache)
|
||||
|
||||
@ -48,35 +48,54 @@ public class MarketDataService : IMarketDataService
|
||||
public async Task<MarketPriceResponse> GetPriceAsync(string symbol, string assetType)
|
||||
{
|
||||
var cacheKey = $"{symbol.ToUpper()}_{assetType.ToUpper()}";
|
||||
_logger.LogInformation("获取实时价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType);
|
||||
|
||||
// 先查缓存
|
||||
var cached = await _marketDataRepo.GetPriceCacheAsync(symbol, assetType);
|
||||
|
||||
if (cached != null)
|
||||
{
|
||||
_logger.LogDebug("缓存命中: {Symbol} {AssetType}, 价格: {Price}", symbol, assetType, cached.Price);
|
||||
return new MarketPriceResponse
|
||||
{
|
||||
Symbol = cached.Symbol,
|
||||
Price = cached.Price,
|
||||
PreviousClose = cached.PreviousClose ?? 0,
|
||||
Timestamp = cached.FetchedAt,
|
||||
AssetType = cached.AssetType
|
||||
};
|
||||
}
|
||||
|
||||
// 使用 GetOrAdd 模式防止并发重复请求
|
||||
var priceTask = _pendingPriceRequests.GetOrAdd(cacheKey, _ => FetchPriceFromSourceAsync(symbol, assetType));
|
||||
_logger.LogInformation("[价格查询开始] Symbol={Symbol}, AssetType={AssetType}, CacheKey={CacheKey}", symbol, assetType, cacheKey);
|
||||
|
||||
try
|
||||
{
|
||||
return await priceTask;
|
||||
// 先查缓存
|
||||
var cached = await _marketDataRepo.GetPriceCacheAsync(symbol, assetType);
|
||||
|
||||
if (cached != null && cached.Price > 0) // ← 验证价格有效
|
||||
{
|
||||
_logger.LogInformation("[缓存命中] Symbol={Symbol}, Price={Price}, ExpiredAt={ExpiredAt}", symbol, cached.Price, cached.ExpiredAt);
|
||||
return new MarketPriceResponse
|
||||
{
|
||||
Symbol = cached.Symbol,
|
||||
Price = cached.Price,
|
||||
PreviousClose = cached.PreviousClose ?? 0,
|
||||
Timestamp = cached.FetchedAt,
|
||||
AssetType = cached.AssetType
|
||||
};
|
||||
}
|
||||
|
||||
if (cached != null && cached.Price <= 0)
|
||||
{
|
||||
_logger.LogWarning("[缓存命中但价格无效] Symbol={Symbol}, Price={Price},忽略缓存重新获取", symbol, cached.Price);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("[缓存未命中] Symbol={Symbol}, AssetType={AssetType},需要从数据源获取", symbol, assetType);
|
||||
}
|
||||
|
||||
// 使用 GetOrAdd 模式防止并发重复请求
|
||||
var priceTask = _pendingPriceRequests.GetOrAdd(cacheKey, _ => FetchPriceFromSourceAsync(symbol, assetType));
|
||||
|
||||
try
|
||||
{
|
||||
var result = await priceTask;
|
||||
_logger.LogInformation("[价格获取成功] Symbol={Symbol}, Price={Price}", symbol, result.Price);
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 请求完成后移除(无论成功失败)
|
||||
_pendingPriceRequests.TryRemove(cacheKey, out _);
|
||||
}
|
||||
}
|
||||
finally
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 请求完成后移除(无论成功失败)
|
||||
_pendingPriceRequests.TryRemove(cacheKey, out _);
|
||||
_logger.LogError(ex, "[价格获取异常] Symbol={Symbol}, AssetType={AssetType}", symbol, assetType);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,6 +139,13 @@ public class MarketDataService : IMarketDataService
|
||||
}
|
||||
}
|
||||
|
||||
// 验证价格有效性
|
||||
if (response.Price <= 0)
|
||||
{
|
||||
_logger.LogError("[价格无效] Symbol={Symbol}, Price={Price}, Source={Source},不写入缓存", symbol, response.Price, source);
|
||||
throw new InvalidOperationException($"获取到的价格无效: {symbol} = {response.Price}");
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
await SavePriceCacheAsync(symbol, assetType, response, source);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user