diff --git a/src/SimpleCronWorkerService/CronWorkerService.cs b/src/SimpleCronWorkerService/CronWorkerService.cs index 8b6e2e5..5b110e0 100644 --- a/src/SimpleCronWorkerService/CronWorkerService.cs +++ b/src/SimpleCronWorkerService/CronWorkerService.cs @@ -9,7 +9,7 @@ namespace SimpleCronWorkerService { public abstract class CronWorkerService : BackgroundService { - private Timer? _timer; + private Timer _timer; private readonly CronExpression _cronExpression; @@ -24,59 +24,63 @@ public CronWorkerService(ICronWorkerServiceSettings settings) : CronExpression.Parse(settings.CronExpression); _timeZone = settings.TimeZone ?? TimeZoneInfo.Utc; + + _timer = new Timer + { + AutoReset = false + }; } protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - try + await RestartTimer(cancellationToken); + + _timer.Elapsed += async (sender, args) => { - var next = _cronExpression.GetNextOccurrence(DateTimeOffset.Now, _timeZone); - if (!next.HasValue) + _timer.Stop(); + + if (!cancellationToken.IsCancellationRequested) { - return; - } + var doWorkTask = DoWork(cancellationToken); - var delay = GetDelay(next.Value); + var restartTimerTask = RestartTimer(cancellationToken); - // If it is a value greater than the MaxValue of Int, - // we have to wait for this difference to decrease. - // I wait for the same amount as MaxValue minus one minute and - // then validate again if it could be a valid value for the Timer. - while (delay.TotalMilliseconds > int.MaxValue) - { - await Task.Delay(DelayMaxValueMilliseconds, cancellationToken); - delay = GetDelay(next.Value); + await doWorkTask; + await restartTimerTask; } + }; - if (delay.TotalMilliseconds <= 0 ) - { - await ExecuteAsync(cancellationToken); - return; - } + await Task.CompletedTask; + } - _timer = new Timer(delay.TotalMilliseconds); - _timer.Elapsed += async (sender, args) => - { - _timer.Dispose(); - _timer = null; - - if (!cancellationToken.IsCancellationRequested) - { - var doWorkTask = DoWork(cancellationToken); - var executeTask = ExecuteAsync(cancellationToken); - - await doWorkTask; - await executeTask; - } - }; - _timer.Start(); + private async Task RestartTimer(CancellationToken cancellationToken) + { + var next = _cronExpression.GetNextOccurrence(DateTimeOffset.Now, _timeZone); + if (!next.HasValue) + { + return; } - catch (OperationCanceledException) + + var delay = GetDelay(next.Value); + + // If it is a value greater than the MaxValue of Int, + // we have to wait for this difference to decrease. + // I wait for the same amount as MaxValue minus one minute and + // then validate again if it could be a valid value for the Timer. + while (delay.TotalMilliseconds > int.MaxValue) { - Console.WriteLine("CronWorkerService was cancelled"); + await Task.Delay(DelayMaxValueMilliseconds, cancellationToken); + delay = GetDelay(next.Value); } - await Task.CompletedTask; + if (delay.TotalMilliseconds <= 0) + { + await RestartTimer(cancellationToken); + return; + } + + _timer.Interval = delay.TotalMilliseconds; + _timer.Start(); } private TimeSpan GetDelay(DateTimeOffset nextValue) => nextValue - DateTimeOffset.Now;