How to start my Worker Service on the hour

Viewed 570

I have this worker service kicking off jobs but hourly it checks for jobs. How can I get it to check on the hour rather at the run time hourly?

public class WorkerService : BackgroundService
{
    private const int generalDelay = 20;  //minutes

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(generalDelay * 60000, stoppingToken);
            await DoBackupAsync();
        }
    }

    private static Task DoBackupAsync()
    {
        DoWork d = new DoWork();
        return Task.FromResult("Done");
    }
}

Mainly for this I know when jobs will run and can predict as well as scheduling my updates in between the run times and if all jobs complete.

5 Answers

For this kind of requirement, a full-blown scheduler may be overkill. I do recommend using a cron expression, but I prefer Cronos over NCrontab. Cronos has better tests and well-defined behavior regarding UTC and daylight saving time transitions.

This is what it would look like using Cronos:

public class WorkerService : BackgroundService
{
  private const string schedule = "0 * * * *"; // every hour
  private readonly CronExpression _cron;

  public WorkerService()
  {
    _cron = CronExpression.Parse(schedule);
  }

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      var utcNow = DateTime.UtcNow;
      var nextUtc = _cron.GetNextOccurrence(utcNow);
      await Task.Delay(nextUtc.Value - utcNow, stoppingToken);
      await DoBackupAsync();
    }
  }
}

You might look for a scheduler as @Paweł Łukasik say, which is very suitable to use the crontab format.

quartz was a powerful library which good to control the job time, but quartz need to cooperate with its library architecture

If your code is huge and difficult to modify, I would suggest you use a light way library NCrontab that can only get the time by crontab.

0 * * * *

Then you can calculate next the hour by GetNextOccurrence method.

public class WorkerService : BackgroundService
{
    const string EveryHours = "0 * * * *";
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var schedule = CrontabSchedule.Parse(EveryHours);
        while (!stoppingToken.IsCancellationRequested)
        {
            var now = DateTime.Now;
            DateTime nextExecutionTime = schedule.GetNextOccurrence(now);
            await Task.Delay((nextExecutionTime - now).Milliseconds, stoppingToken);
            await DoBackupAsync();
        }
    }
    private static Task DoBackupAsync()
    {
        DoWork d = new DoWork();
        return Task.FromResult("Done");
    }
}

If you want to check the current hour you can use var datetime = DateTime.UtcNow which will take the current DateTime, and then you can use datetime.Hour to get the current hour value so you can use it to check.

You could use the WaitUntilNextHourAsync method below:

public static Task WaitUntilNextHourAsync(
    CancellationToken cancellationToken = default)
{
    DateTime now = DateTime.Now;
    DateTime next = now.Date.AddHours(now.Hour + 1);
    Debug.Assert(next > now);
    TimeSpan delay = next - now;
    Debug.Assert(delay > TimeSpan.Zero && delay.TotalHours <= 1);
    if (delay.TotalSeconds < 1) delay += TimeSpan.FromHours(1);
    return Task.Delay(delay, cancellationToken);
}

Usage example:

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (true)
    {
        await WaitUntilNextHourAsync(stoppingToken);
        await DoBackupAsync();
    }
}

I was starting off with something similar to the accepted answer - you probably don't need anything more. However, I was ending up sharing my code as a github/nuget project. It's by far more basic (and easy to use) than Quartz.NET and other scheduling frameworks. Give it a try and let me know via github issues if something doesn't work as expected.

The source code repository: https://github.com/thomasgalliker/NCrontab.Scheduler

The nuget download: https://www.nuget.org/packages/NCrontab.Scheduler

Enjoy.

Related