Add healthchecks for all candles + Claim ui fee button

This commit is contained in:
2025-10-29 09:31:00 +07:00
parent 28f2daeb05
commit 29685fd68d
9 changed files with 754 additions and 7 deletions

View File

@@ -0,0 +1,142 @@
using Managing.Application.Abstractions.Services;
using Managing.Common;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using static Managing.Common.Enums;
namespace Managing.Api.HealthChecks
{
public class CandleDataDetailedHealthCheck : IHealthCheck
{
private readonly IExchangeService _exchangeService;
private readonly TradingExchanges _exchangeToCheck = TradingExchanges.Evm;
public CandleDataDetailedHealthCheck(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.FiveMinutes, startDate: now.AddDays(-1), maxAgeMins: 7),
(timeframe: Timeframe.FifteenMinutes, startDate: now.AddDays(-1), maxAgeMins: 17),
(timeframe: Timeframe.OneHour, startDate: now.AddDays(-3), maxAgeMins: 62),
(timeframe: Timeframe.FourHour, startDate: now.AddDays(-7), maxAgeMins: 242),
(timeframe: Timeframe.OneDay, startDate: now.AddDays(-30), maxAgeMins: 1442)
};
var supportedTickers = Constants.GMX.Config.SupportedTickers;
var tickerResults = new Dictionary<string, object>();
var isHealthy = true;
var totalChecks = 0;
var healthyChecks = 0;
var degradedChecks = 0;
foreach (var ticker in supportedTickers)
{
var degradedTimeframeResults = new List<Dictionary<string, object>>();
foreach (var (timeframe, startDate, maxAgeMins) in timeframeChecks)
{
totalChecks++;
// Fetch candles for this ticker and timeframe
var candles = await _exchangeService.GetCandlesInflux(
_exchangeToCheck,
ticker,
startDate,
timeframe);
if (candles == null || !candles.Any())
{
var checkResult = new Dictionary<string, object>
{
["Timeframe"] = timeframe.ToString(),
["StartDate"] = startDate,
["Status"] = "Degraded",
["Message"] = $"No candle data found for {ticker} - {timeframe}"
};
degradedTimeframeResults.Add(checkResult);
isHealthy = false;
degradedChecks++;
}
else
{
var latestCandle = candles.OrderByDescending(c => c.Date).FirstOrDefault();
var timeDiff = now - latestCandle.Date;
if (timeDiff.TotalMinutes > maxAgeMins)
{
var checkResult = new Dictionary<string, object>
{
["Timeframe"] = timeframe.ToString(),
["StartDate"] = startDate,
["LatestCandleDate"] = latestCandle.Date,
["TimeDifference"] = $"{timeDiff.TotalMinutes:F2} minutes",
["CandleCount"] = candles.Count(),
["Status"] = "Degraded",
["Message"] = $"Data for {ticker} - {timeframe} is outdated. Latest candle is from {latestCandle.Date:yyyy-MM-dd HH:mm:ss} UTC"
};
degradedTimeframeResults.Add(checkResult);
isHealthy = false;
degradedChecks++;
}
else
{
healthyChecks++;
}
}
}
// Only add ticker to results if it has degraded checks
if (degradedTimeframeResults.Any())
{
tickerResults[ticker.ToString()] = degradedTimeframeResults;
}
}
// Build summary
var summary = new Dictionary<string, object>
{
["TotalChecks"] = totalChecks,
["HealthyChecks"] = healthyChecks,
["DegradedChecks"] = degradedChecks,
["CheckedTickers"] = supportedTickers.Select(t => t.ToString()).ToArray(),
["CheckedTimeframes"] = timeframeChecks.Select(tc => tc.timeframe.ToString()).ToArray(),
["TickerResults"] = tickerResults
};
if (isHealthy)
{
return HealthCheckResult.Healthy(
$"All candle data is up-to-date for {supportedTickers.Length} tickers across {timeframeChecks.Length} timeframes",
data: summary);
}
else
{
return HealthCheckResult.Degraded(
$"{degradedChecks} out of {totalChecks} candle checks are outdated or missing",
data: summary);
}
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy(
"Error checking detailed candle data health",
ex,
data: new Dictionary<string, object>
{
["ErrorMessage"] = ex.Message,
["ErrorType"] = ex.GetType().Name
});
}
}
}
}