feat: add background task
This commit is contained in:
@ -0,0 +1,121 @@
|
||||
using Cronos;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mirea.Api.Endpoint.Common.Services;
|
||||
using Mirea.Api.Endpoint.Configuration.Model;
|
||||
using Mirea.Api.Endpoint.Sync;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using IServiceProvider = System.IServiceProvider;
|
||||
|
||||
namespace Mirea.Api.Endpoint.Configuration.Core.BackgroundTasks;
|
||||
|
||||
public class ScheduleSyncService : IHostedService, IDisposable
|
||||
{
|
||||
private Timer? _timer;
|
||||
private readonly IOptionsMonitor<GeneralConfig> _generalConfigMonitor;
|
||||
private readonly ILogger<ScheduleSyncService> _logger;
|
||||
private CancellationTokenSource _cancellationTokenSource = new();
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ScheduleSyncService(IOptionsMonitor<GeneralConfig> generalConfigMonitor, ILogger<ScheduleSyncService> logger, IServiceProvider serviceProvider)
|
||||
{
|
||||
_generalConfigMonitor = generalConfigMonitor;
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
|
||||
ScheduleSyncManager.OnForceSyncRequested += OnForceSyncRequested;
|
||||
ScheduleSyncManager.OnUpdateIntervalRequested += OnUpdateIntervalRequested;
|
||||
}
|
||||
|
||||
private void OnForceSyncRequested()
|
||||
{
|
||||
StopAsync(default).ContinueWith(_ =>
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
ExecuteTask(null);
|
||||
});
|
||||
}
|
||||
|
||||
private void OnUpdateIntervalRequested()
|
||||
{
|
||||
StopAsync(default).ContinueWith(_ =>
|
||||
{
|
||||
StartAsync(default);
|
||||
});
|
||||
}
|
||||
|
||||
private void ScheduleNextRun()
|
||||
{
|
||||
var cronExpression = _generalConfigMonitor.CurrentValue.ScheduleSettings?.CronUpdateSchedule;
|
||||
if (string.IsNullOrEmpty(cronExpression))
|
||||
{
|
||||
_logger.LogWarning("Cron expression is not set. The scheduled task will not run.");
|
||||
return;
|
||||
}
|
||||
|
||||
var nextRunTime = CronExpression.Parse(cronExpression).GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Local);
|
||||
|
||||
if (!nextRunTime.HasValue)
|
||||
{
|
||||
_logger.LogWarning("No next run time found. The task will not be scheduled. Timezone: {TimeZone}", TimeZoneInfo.Local.DisplayName);
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Next task run in {Time}", nextRunTime.Value.ToString("G"));
|
||||
|
||||
var delay = (nextRunTime.Value - DateTimeOffset.Now).TotalMilliseconds;
|
||||
|
||||
// The chance is small, but it's better to check
|
||||
if (delay <= 0)
|
||||
delay = 1;
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
_timer = new Timer(ExecuteTask, null, (int)delay, Timeout.Infinite);
|
||||
}
|
||||
|
||||
private async void ExecuteTask(object? state)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var syncService = ActivatorUtilities.GetServiceOrCreateInstance<ScheduleSynchronizer>(scope.ServiceProvider);
|
||||
await syncService.StartSync(_cancellationTokenSource.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error occurred during schedule synchronization.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
ScheduleNextRun();
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
ScheduleNextRun();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
_timer?.Change(Timeout.Infinite, 0);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StopAsync(default).GetAwaiter().GetResult();
|
||||
_timer?.Dispose();
|
||||
ScheduleSyncManager.OnForceSyncRequested -= OnForceSyncRequested;
|
||||
ScheduleSyncManager.OnUpdateIntervalRequested -= OnUpdateIntervalRequested;
|
||||
_cancellationTokenSource.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user