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.
CodePudding user response:
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 = expression.GetNextOccurrence(utcNow);
await Task.Delay(utcNow - nextUtc.Value, stoppingToken);
await DoBackupAsync();
}
}
}
CodePudding user response:
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");
}
}
CodePudding user response:
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.
CodePudding user response:
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();
}
}