Fixed semaphore not being released.

Added delay until next minute.
Updated how the option setup works.
This commit is contained in:
Tyler Coles 2023-10-13 15:15:17 -04:00
parent e3d387b2cd
commit 700bf3abe3
3 changed files with 49 additions and 20 deletions

View File

@ -1,18 +1,21 @@
using crondotnet;
using crondotnet.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
public static class CronServiceProverExtensions
{
public static IServiceCollection AddCron(this IServiceCollection services, Action<ICronDaemonOptionsBuilder>? optionsAction = null)
public static IServiceCollection AddCron(this IServiceCollection services, Action<ICronDaemonOptionsBuilder>? cronBuilder = null)
{
services.AddSingleton<CronDaemonHostedService>();
services.AddHostedService<CronDaemonHostedService>();
services.AddScoped<ICronDaemon, CronDaemon>();
var cronDaemonOptionsBuilder = new CronDaemonOptionsBuilder();
optionsAction?.Invoke(cronDaemonOptionsBuilder);
services.ConfigureOptions(cronDaemonOptionsBuilder.Build());
var cronDaemonOptionsBuilder = new CronDaemonOptionsBuilder(services);
cronBuilder?.Invoke(cronDaemonOptionsBuilder);
services.AddOptions<CronDaemonOptions>()
.Configure(options => cronDaemonOptionsBuilder.Bind(options));
return services;
}
@ -27,11 +30,17 @@ namespace Microsoft.Extensions.DependencyInjection
public class CronDaemonOptionsBuilder : ICronDaemonOptionsBuilder
{
private readonly CronDaemonOptions Options = new CronDaemonOptions();
private readonly List<JobOptions> Jobs = new List<JobOptions>();
private IServiceCollection services;
public CronDaemonOptionsBuilder(IServiceCollection services)
{
this.services = services;
}
public ICronDaemonOptionsBuilder AddJob(string cronExpression, ExecuteCronJob job)
{
Options.Jobs.Add(new JobOptions
Jobs.Add(new JobOptions
{
Expression = cronExpression,
StaticTask = job
@ -43,18 +52,23 @@ namespace Microsoft.Extensions.DependencyInjection
public ICronDaemonOptionsBuilder AddJob<TService>(string cronExpression)
where TService : IThinService
{
Options.Jobs.Add(new JobOptions
Jobs.Add(new JobOptions
{
Expression = cronExpression,
ServiceType = typeof(TService),
});
services.TryAddScoped(typeof(TService));
return this;
}
internal CronDaemonOptions Build()
internal void Bind(CronDaemonOptions options)
{
return Options;
foreach (var job in Jobs)
{
options.Jobs.Add(job);
}
}
}
}

View File

@ -16,7 +16,6 @@ namespace crondotnet
{
private readonly PeriodicTimer timer;
private readonly List<ICronJob> cronJobs = new List<ICronJob>();
private DateTime _last = DateTime.Now;
private CancellationTokenSource tokenSource = null;
private Task timerTask = null;
@ -50,18 +49,27 @@ namespace crondotnet
private async Task InternalStart(CancellationToken cancellationToken)
{
var currentTime = DateTime.Now;
var targetTime = currentTime.Date.AddHours(currentTime.Hour).AddMinutes(currentTime.Minute + 1);
// .AddSeconds(currentTime.Second + (30 - (currentTime.Second % 30))); // If we wanted to increase resolution, this would allow for specify second targetting.
DateTime? lastRun = null;
// wait until the next 30 second interval before starting to trigger.
await Task.Delay(targetTime - currentTime);
while (!cancellationToken.IsCancellationRequested)
{
try
{
await timer.WaitForNextTickAsync(cancellationToken);
if (!cancellationToken.IsCancellationRequested && DateTime.Now.Minute != _last.Minute)
if (!cancellationToken.IsCancellationRequested && (!lastRun.HasValue || DateTime.Now.Minute != lastRun.Value.Minute))
{
_last = DateTime.Now;
lastRun = DateTime.Now;
foreach (ICronJob job in cronJobs)
job.Execute(DateTime.Now, cancellationToken);
job.Execute(lastRun.Value, cancellationToken);
}
await timer.WaitForNextTickAsync(cancellationToken);
}
catch (TaskCanceledException)
{

View File

@ -25,12 +25,19 @@ namespace crondotnet
public async Task Execute(DateTime startTime, CancellationToken cancellationToken)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
await _semaphore.WaitAsync(cancellationToken);
if (!_cronSchedule.IsTime(startTime))
return;
if (!_cronSchedule.IsTime(startTime))
return;
await _threadStart(cancellationToken);
await _threadStart(cancellationToken);
}
finally
{
_semaphore.Release();
}
}
}
}