Files
managing-apps/src/Managing.Api/HealthChecks/CandleDataHealthCheck.cs
2025-04-25 13:34:59 +07:00

114 lines
4.8 KiB
C#

using Managing.Application.Abstractions.Services;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using static Managing.Common.Enums;
namespace Managing.Api.HealthChecks
{
public class CandleDataHealthCheck : IHealthCheck
{
private readonly IExchangeService _exchangeService;
private readonly Ticker _tickerToCheck = Ticker.ETH;
private readonly TradingExchanges _exchangeToCheck = TradingExchanges.Evm;
public CandleDataHealthCheck(IExchangeService exchangeService)
{
_exchangeService = exchangeService;
}
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
var now = DateTime.UtcNow;
// Define timeframes to check with their appropriate start dates and expected freshness
var timeframeChecks = new[]
{
(timeframe: Timeframe.FifteenMinutes, startDate: now.AddDays(-1), maxAgeMins: 30.0),
(timeframe: Timeframe.OneHour, startDate: now.AddDays(-3), maxAgeMins: 120.0),
(timeframe: Timeframe.OneDay, startDate: now.AddDays(-30), maxAgeMins: 1440.0)
};
var results = new List<Dictionary<string, object>>();
var isHealthy = true;
foreach (var (timeframe, startDate, maxAgeMins) in timeframeChecks)
{
// Using configured exchange and ticker
var candles = await _exchangeService.GetCandlesInflux(
_exchangeToCheck,
_tickerToCheck,
startDate,
timeframe);
var checkResult = new Dictionary<string, object>
{
["CheckedTicker"] = _tickerToCheck.ToString(),
["CheckedTimeframe"] = timeframe.ToString(),
["StartDate"] = startDate
};
if (candles == null || !candles.Any())
{
checkResult["Status"] = "Degraded";
checkResult["Message"] = $"No candle data found for {timeframe}";
isHealthy = false;
}
else
{
var latestCandle = candles.OrderByDescending(c => c.Date).FirstOrDefault();
var timeDiff = now - latestCandle.Date;
checkResult["LatestCandleDate"] = latestCandle.Date;
checkResult["TimeDifference"] = $"{timeDiff.TotalMinutes:F2} minutes";
if (timeDiff.TotalMinutes > maxAgeMins)
{
checkResult["Status"] = "Degraded";
checkResult["Message"] = $"Data for {timeframe} is outdated. Latest candle is from {latestCandle.Date:yyyy-MM-dd HH:mm:ss} UTC";
isHealthy = false;
}
else
{
checkResult["Status"] = "Healthy";
checkResult["Message"] = $"Data for {timeframe} is up-to-date. Latest candle is from {latestCandle.Date:yyyy-MM-dd HH:mm:ss} UTC";
}
}
results.Add(checkResult);
}
// Combine all results into a summary
var resultsDictionary = new Dictionary<string, object>();
for (int i = 0; i < results.Count; i++)
{
resultsDictionary[$"TimeframeCheck_{i+1}"] = results[i];
}
if (isHealthy)
{
return HealthCheckResult.Healthy(
"All candle timeframes are up-to-date",
data: resultsDictionary);
}
else
{
return HealthCheckResult.Degraded(
"One or more candle timeframes are outdated or missing",
data: resultsDictionary);
}
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy(
"Error checking candle data health",
ex,
data: new Dictionary<string, object>
{
["ErrorMessage"] = ex.Message,
["ErrorType"] = ex.GetType().Name
});
}
}
}
}