using Amazon.DynamoDBv2.Model; using ServerCore; using ServerBase; namespace UGQApiServer.BackGroundService; public static class BackgroundServiceExtensions { public static IServiceCollection AddOnTimeBackgroundService(this IServiceCollection services) { services.AddSingleton(); services.AddHostedService(provider => provider.GetRequiredService()); return services; } public static IServiceCollection AddOnTimeTask(this IServiceCollection services, string taskName, DateTime onTime, Task task) { var provider = services.BuildServiceProvider(); var service = provider.GetRequiredService(); service.addOnTimeTask(taskName, onTime, task); return services; } } public class OnTimeBackGroundService : BackgroundService { private const int BaseDelayMs = 1_000; private PeriodicTimer? m_timer { get; set; } private Dictionary m_onTime_tasks { get; set; } = new(); public OnTimeBackGroundService() {} public override void Dispose() { base.Dispose(); m_timer?.Dispose(); GC.SuppressFinalize(this); } public bool addOnTimeTask(string taskName, DateTime onTime, Task action) { return m_onTime_tasks.TryAdd(taskName, (action, onTime)); } public bool deleteOnTimeTask(string taskName) { return m_onTime_tasks.Remove(taskName); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { CreateTimer(); try { if (!await m_timer!.WaitForNextTickAsync(stoppingToken).ConfigureAwait(false)) { return; } while (!stoppingToken.IsCancellationRequested) { await RunAsync().ConfigureAwait(false); if (!await m_timer!.WaitForNextTickAsync(stoppingToken).ConfigureAwait(false)) { break; } } } catch (Exception e) { Log.getLogger().error($"Background Exception : {e.Message}"); } } private async Task RunAsync() { var current = DateTime.UtcNow; foreach (var task in m_onTime_tasks) { var on_time = task.Value.time; if (current.Hour != on_time.Hour || current.Minute != on_time.Minute || current.Second != on_time.Second) continue; // Fire and Forget _ = Task.Run(() => task.Value.task); } await Task.CompletedTask; } private void CreateTimer() => m_timer = new PeriodicTimer(TimeSpan.FromMilliseconds(BaseDelayMs)); }