Skip to content

Commit

Permalink
add scheduler worker
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan committed Apr 8, 2024
1 parent d58318f commit 00ed269
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/Hosting/Hosting/src/ClickView.Extensions.Hosting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Cronos" Version="0.8.4" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
</ItemGroup>

</Project>
84 changes: 84 additions & 0 deletions src/Hosting/Hosting/src/Workers/SchedulerWorker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
namespace ClickView.Extensions.Hosting.Workers;

using System;
using System.Threading;
using System.Threading.Tasks;
using Cronos;
using Microsoft.Extensions.Logging;

public abstract class SchedulerWorker : Worker, IDisposable
{
private readonly ILogger _logger;
private Timer? _timer;
private CancellationTokenSource? _cancellationTokenSource;

protected abstract string CronSchedule { get; }

protected SchedulerWorker(ILogger logger) : base(logger)
{
_logger = logger;
}

protected override Task ExecuteAsync(CancellationToken cancellationToken)
{
var dueTime = GetNextScheduleDelay();
if (!dueTime.HasValue)
throw new Exception("Failed to get next schedule");

_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_timer = new Timer(_ => TimerCallbackAsync(_cancellationTokenSource.Token), null, dueTime.Value, Timeout.InfiniteTimeSpan);

return Task.CompletedTask;
}

private async void TimerCallbackAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return;

try
{
await RunAsync(cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception caught in SchedulerWorker ({WorkerName})", Name);
}
finally
{
var dueTime = GetNextScheduleDelay();
if (dueTime.HasValue)
{
// Reschedule the timer
_timer?.Change(dueTime.Value, Timeout.InfiniteTimeSpan);
}
else
{
_logger.LogError("Unable to get the next schedule in SchedulerWorker ({WorkerName})", Name);
}
}
}

private TimeSpan? GetNextScheduleDelay()
{
var now = DateTime.UtcNow;

var cronValue = CronExpression.Parse(CronSchedule);
var next = cronValue.GetNextOccurrence(now);
if (!next.HasValue)
return null;

return next.Value - now;
}

public void Dispose()
{
_cancellationTokenSource?.Cancel();

// Stop the timer
_timer?.Change(Timeout.Infinite, 0);
_timer?.Dispose();
}

protected abstract Task RunAsync(CancellationToken cancellationToken);
}

0 comments on commit 00ed269

Please sign in to comment.