如何按小时启动我的 Worker Service
How to start my Worker Service on the hour
我有这个工人服务开始工作,但它每小时检查一次工作。我怎样才能让它按小时而不是每小时 运行 时间检查?
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");
}
}
主要是因为我知道作业何时会 运行 并且可以预测和安排我的更新在 运行 时间之间以及所有作业是否完成。
如果您想查看当前时间,您可以使用
var datetime = DateTime.UtcNow
这将采用当前的日期时间,然后您可以使用
datetime.Hour
获取当前小时值,以便您可以使用它来检查。
您可能会像@Paweł Łukasik 说的那样寻找一个调度程序,它非常适合使用 crontab 格式。
quartz是一个强大的库,可以很好的控制作业时间,但是quartz需要配合它的库架构
如果你的代码比较庞大,难以修改,我建议你使用一个只能通过crontab获取时间的轻型库NCrontab。
0 * * * *
然后你可以用GetNextOccurrence
方法计算下一个小时
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");
}
}
您可以使用下面的WaitUntilNextHourAsync
方法:
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);
}
用法示例:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (true)
{
await WaitUntilNextHourAsync(stoppingToken);
await DoBackupAsync();
}
}
对于这种要求,full-blown 调度程序可能有点矫枉过正。我建议使用 cron 表达式,但我更喜欢 Cronos 而不是 NCrontab。 Cronos 在 UTC 和夏令时转换方面有更好的测试和 well-defined 行为。
这是使用 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();
}
}
}
我从类似于已接受答案的内容开始 - 您可能不需要更多内容。但是,我最终将我的代码作为 github/nuget 项目共享。它比 Quartz.NET 和其他调度框架更基础(也更易于使用)。
试一试,如果有什么不能按预期工作,请通过 github 问题告诉我。
源代码库:
https://github.com/thomasgalliker/NCrontab.Scheduler
nuget 下载:
https://www.nuget.org/packages/NCrontab.Scheduler
尽情享受吧。
我有这个工人服务开始工作,但它每小时检查一次工作。我怎样才能让它按小时而不是每小时 运行 时间检查?
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");
}
}
主要是因为我知道作业何时会 运行 并且可以预测和安排我的更新在 运行 时间之间以及所有作业是否完成。
如果您想查看当前时间,您可以使用
var datetime = DateTime.UtcNow
这将采用当前的日期时间,然后您可以使用
datetime.Hour
获取当前小时值,以便您可以使用它来检查。
您可能会像@Paweł Łukasik 说的那样寻找一个调度程序,它非常适合使用 crontab 格式。
quartz是一个强大的库,可以很好的控制作业时间,但是quartz需要配合它的库架构
如果你的代码比较庞大,难以修改,我建议你使用一个只能通过crontab获取时间的轻型库NCrontab。
0 * * * *
然后你可以用GetNextOccurrence
方法计算下一个小时
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");
}
}
您可以使用下面的WaitUntilNextHourAsync
方法:
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);
}
用法示例:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (true)
{
await WaitUntilNextHourAsync(stoppingToken);
await DoBackupAsync();
}
}
对于这种要求,full-blown 调度程序可能有点矫枉过正。我建议使用 cron 表达式,但我更喜欢 Cronos 而不是 NCrontab。 Cronos 在 UTC 和夏令时转换方面有更好的测试和 well-defined 行为。
这是使用 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();
}
}
}
我从类似于已接受答案的内容开始 - 您可能不需要更多内容。但是,我最终将我的代码作为 github/nuget 项目共享。它比 Quartz.NET 和其他调度框架更基础(也更易于使用)。 试一试,如果有什么不能按预期工作,请通过 github 问题告诉我。
源代码库: https://github.com/thomasgalliker/NCrontab.Scheduler
nuget 下载: https://www.nuget.org/packages/NCrontab.Scheduler
尽情享受吧。