Backend/e-suite.Scheduler/e-suite.Scheduler/TimedHostedService.cs
2026-01-20 21:50:10 +00:00

110 lines
3.2 KiB
C#

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Timers;
using e_suite.Scheduler.Jobs;
using e_suite.Scheduler.Scheduler;
using eSuite.Core.Clock;
namespace e_suite.Scheduler;
public class TimedHostedService : IHostedService
{
private readonly List<ScheduledJob> _jobs = [];
private readonly ILogger _logger;
private readonly IServiceProvider _serviceProvider;
private readonly IClock _clock;
private readonly System.Timers.Timer _timer;
public TimedHostedService(ILogger logger, IServiceProvider serviceProvider, IClock clock )
{
_timer = new System.Timers.Timer
{
Interval = 10000,
AutoReset = true,
};
_timer.Elapsed += ExecuteTimer;
_logger = logger;
_serviceProvider = serviceProvider;
_clock = clock;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
RegisterJobs();
_timer.Enabled = true;
ExecuteTimer(_timer, null!);
return Task.CompletedTask;
}
private void RegisterJobs()
{
RegisterJob<NightlyCleanUp>();
RegisterJob<NightlySigmaImport>();
}
private void RegisterJob<T>() where T : IJob
{
var schedule = GetSchedule(typeof(T));
var scheduledJob = new ScheduledJob(_clock)
{
Schedule = schedule,
#pragma warning disable CS8601 //Null reference is checked for so no need to worry about it here.
Job = _serviceProvider.GetService(typeof(T)) as IJob,
#pragma warning restore CS8601
LastExecuted = _clock.GetNow
};
if (scheduledJob.Job == null)
throw new ArgumentNullException(nameof(scheduledJob.Job), "job cannot be null");
_jobs.Add(scheduledJob);
}
private static ISchedule GetSchedule(Type type)
{
var attributes = type.GetCustomAttributes(false);
foreach (var attribute in attributes)
{
if (attribute is ISchedule schedule)
return schedule;
}
throw new InvalidOperationException($"{type.FullName} does not contain a valid Schedule attribute");
}
private void ExecuteTimer(object? sender, ElapsedEventArgs e)
{
var now = _clock.GetNow;
var taskList = new List<Task>();
foreach (var job in _jobs.Where(job => job.NextScheduledExecution <= now))
{
job.LastExecuted = now;
taskList.Add(ExecuteJobAsync(job.Job));
}
Task.WhenAll(taskList).GetAwaiter().GetResult();
}
private async Task ExecuteJobAsync(IJob job)
{
_logger.LogInformation("Executing {FullName}", job.GetType().FullName);
await job.ExecuteAsync();
_logger.LogInformation("Executing {FullName} - Completed", job.GetType().FullName);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_jobs.Clear();
return Task.CompletedTask;
}
}