Skip to content

Commit

Permalink
feat: change to restart timer
Browse files Browse the repository at this point in the history
  • Loading branch information
alejandropb36 committed May 11, 2023
1 parent 8d935e1 commit 76870b4
Showing 1 changed file with 43 additions and 39 deletions.
82 changes: 43 additions & 39 deletions src/SimpleCronWorkerService/CronWorkerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace SimpleCronWorkerService
{
public abstract class CronWorkerService : BackgroundService
{
private Timer? _timer;
private Timer _timer;

private readonly CronExpression _cronExpression;

Expand All @@ -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;
Expand Down

0 comments on commit 76870b4

Please sign in to comment.