Search code examples
c#asp.net-core.net-corecron

.NET Core 2.2 Scheduled Jobs Prevent Concurrency on same job


This is my class to handle CronJobs. So far it runs fine on its own. However, how can I modify this so that when a job is already running, disallow the same job from running also?

I am not using any library for this.

public abstract class CronJob : IHostedService, IDisposable
 {
     private System.Timers.Timer timer;
     private readonly CronExpression _expression;
     private readonly TimeZoneInfo _timeZoneInfo;

     protected CronJob(string cronExpression, TimeZoneInfo timeZoneInfo)
     {
         _expression = CronExpression.Parse(cronExpression, CronFormat.IncludeSeconds);
         _timeZoneInfo = timeZoneInfo;
     }

     protected virtual async Task ScheduleJob(CancellationToken cancellationToken)
     {
         var next = _expression.GetNextOccurrence(DateTimeOffset.Now, _timeZoneInfo);
         if (next.HasValue)
         {
             var delay = next.Value - DateTimeOffset.Now;
             timer = new System.Timers.Timer(delay.TotalMilliseconds);
             timer.Elapsed += async (sender, args) =>
             {
                 timer.Stop();  // reset timer
                 await DoWork(cancellationToken);
                 await ScheduleJob(cancellationToken);    // reschedule next
             };
             timer.Start();
         }
         await Task.CompletedTask;
     }

     public virtual async Task DoWork(CancellationToken cancellationToken)
     {
         await Task.Delay(5000, cancellationToken);  // do the work
     }

     public virtual async Task StartAsync(CancellationToken cancellationToken)
     {
         await ScheduleJob(cancellationToken);
     }

     public virtual async Task StopAsync(CancellationToken cancellationToken)
     {
         timer?.Stop();
         await Task.CompletedTask;
     }

     public virtual void Dispose()
     {
         timer?.Dispose();
     }
 }

Solution

  • You don't have to because .NET Core handles HostedServices as a Singleton. Unless when it comes to hosting multiple instance of the same project that contains this HostedService, then you would have to support multiple instances for your project on your own.

    In your case,

    This means that ScheduleJob only has its own instance and will never have a deep copy of its own unless you run a separate instance of the project that contains it