chore: initial project import

This commit is contained in:
justme committed 2026-10-04 21:46:39 +08:00
commit 3fc4e5ca53
347 files changed
+56172

No files matched your search

@@ -0,0 +1,77 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Monitor.Backend.Application;
/// <summary>保留清理:原始段文件(持续任务与按需测试保留期不同)、各层指标、事件。保留期来自 settings,可以在线修改。</summary>
public sealed partial class RetentionService : BackgroundService
{
private static readonly TimeSpan s_interval = TimeSpan.FromHours(1);
private readonly IRawStore _raw;
private readonly IMetricStore _metrics;
private readonly IEventStore _events;
private readonly IAuthStore _auth;
private readonly IHostStore _hosts;
private readonly SettingsService _settings;
private readonly LoginRateLimiter _limiter;
private readonly TimeProvider _time;
private readonly ILogger<RetentionService> _logger;
public RetentionService(IRawStore raw, IMetricStore metrics, IEventStore events, IHostStore hosts, IAuthStore auth, SettingsService settings, LoginRateLimiter limiter, TimeProvider time, ILogger<RetentionService> logger)
{
_raw = raw;
_metrics = metrics;
_events = events;
_hosts = hosts;
_auth = auth;
_settings = settings;
_limiter = limiter;
_time = time;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await RunOnceAsync(stoppingToken);
await Task.Delay(s_interval, _time, stoppingToken);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
return;
}
catch (Exception ex)
{
// 后台循环不能因为一次失败而退出
LogFailed(ex);
await Task.Delay(TimeSpan.FromMinutes(5), _time, stoppingToken);
}
}
}
/// <summary>执行一轮清理(也供测试直接调用)。</summary>
public async Task RunOnceAsync(CancellationToken ct)
{
DateTimeOffset now = _time.GetUtcNow();
long nowMs = now.ToUnixTimeMilliseconds();
DateOnly today = DateOnly.FromDateTime(now.UtcDateTime);
int rawDays = await _settings.GetIntAsync(SettingsService.RawDays, ct);
int testDays = await _settings.GetIntAsync(SettingsService.TestRawDays, ct);
await _raw.DeleteExpiredAsync(today.AddDays(-rawDays), today.AddDays(-testDays), ct);
await _metrics.DeleteOlderThanAsync(MetricLevel.S10, nowMs - (await _settings.GetIntAsync(SettingsService.Metric10sHours, ct) * Steps.Hour), ct);
await _metrics.DeleteOlderThanAsync(MetricLevel.M1, nowMs - (await _settings.GetIntAsync(SettingsService.Metric1mDays, ct) * Steps.Day), ct);
await _metrics.DeleteOlderThanAsync(MetricLevel.M5, nowMs - (await _settings.GetIntAsync(SettingsService.Metric5mDays, ct) * Steps.Day), ct);
await _events.DeleteOlderThanAsync(nowMs - (await _settings.GetIntAsync(SettingsService.EventDays, ct) * Steps.Day), ct);
await _hosts.DeleteOlderThanAsync(nowMs - (await _settings.GetIntAsync(SettingsService.HostDays, ct) * Steps.Day), ct);
await _auth.DeleteExpiredSessionsAsync(nowMs, ct);
_limiter.Prune();
}
[LoggerMessage(Level = LogLevel.Error, Message = "retention pass failed")]
private partial void LogFailed(Exception exception);
}