Hangfire RecurringJob 与时钟同步
Hangfire RecurringJob synchronized with the clock
我正在尝试将 Hangfire 重复作业与时钟同步。基本上,我希望从下一个小时开始,然后每个小时都有一份重复性工作。
示例:如果当前时间是 9:04 下午,则重复作业应如下所示:
10:00 下午 -> 11:00 下午,00:00 上午,01:00 上午,02:00 上午等
这与我之前的问题类似:C# Timer ticking on each rounded hour (literally),但使用的是 Hangfire。
在下面的代码中,我尝试首先通过安排一个 BackgroundJob
来安排下一个小时之前的剩余分钟数,然后在执行 BackgroundJob
之后的每个小时安排 RecurringJob
.问题是它会随机计时。
private DateTime RoundCurrentToNextOneHour()
{
DateTime now = DateTime.Now, result = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
return result.AddMinutes(((now.Minute / 60) + 1) * 60);
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
BackgroundJob.Schedule(() => StartRecurringJob(), RoundCurrentToNextOneHour());
return Task.CompletedTask;
}
public void StartRecurringJob()
{
RecurringJob.AddOrUpdate(() => DoWork(), Cron.Hourly, TimeZoneInfo.Local);
}
在这行代码中,您总是增加 60 分钟。
result.AddMinutes(((now.Minute / 60) + 1) * 60)
这是因为 Minute
属性 只能在值 0 到 59 之间,因此减少为:
result.AddMinutes((0 + 1) * 60)
result.AddMinutes(1 * 60)
result.AddMinutes(60)
试试这个:
result.AddMinutes((60 - (now.Minute % 60)) % 60)
例如,09:00
将显示为 09:00
,但 09:01
到 09:59
将四舍五入为 10:00
。听起来这就是您要求的行为。
您可能还想阅读 in the HangFire docs 关于 SchedulePollingInterval
的内容,这可能会影响您的结果。
使用 cron 表达式有更好的方法。如果您打开 https://crontab.guru 并尝试一些表达式,您会找到每个表达式的解释。
一些 cron 表达式的例子:
- 每 5 分钟:
0/5 * * * *
。
如果当前时间是 11:12 下午,它将在 11:15 下午执行一个方法,然后在 11:20 下午等。
- 每小时
0 * * * *
。
如果当前时间是11:12下午,它将在00:00上午、01:00上午、02:00上午等执行一个方法
除了cron 表达式之外,还有内置的cron 表达式。他们的源代码在这里:https://github.com/HangfireIO/Hangfire/blob/9cd09f38fa97e4c2dd48f6097985fd2b48b4568e/src/Hangfire.Core/Cron.cs#L231。如果我想每 1 小时做一些动作,那就是 Cron.Hourly()
.
示例代码如下:
RecurringJobManager manager = new RecurringJobManager();
manager.RemoveIfExists("myjob");
// Each 5 minutes, e.g. 01:05 pm, 01:10 pm, 01:15 pm, etc.
//manager.AddOrUpdate("myjob", Job.FromExpression(() => DoWork()), $"0/5 * * * *", TimeZoneInfo.Local);
// Each 1 hour, e.g. 01:00 pm, 02:00, 03:00 pm, etc.
manager.AddOrUpdate("myjob", Job.FromExpression(() => DoWork()), $"0 * * * *", TimeZoneInfo.Local);
我正在尝试将 Hangfire 重复作业与时钟同步。基本上,我希望从下一个小时开始,然后每个小时都有一份重复性工作。
示例:如果当前时间是 9:04 下午,则重复作业应如下所示: 10:00 下午 -> 11:00 下午,00:00 上午,01:00 上午,02:00 上午等
这与我之前的问题类似:C# Timer ticking on each rounded hour (literally),但使用的是 Hangfire。
在下面的代码中,我尝试首先通过安排一个 BackgroundJob
来安排下一个小时之前的剩余分钟数,然后在执行 BackgroundJob
之后的每个小时安排 RecurringJob
.问题是它会随机计时。
private DateTime RoundCurrentToNextOneHour()
{
DateTime now = DateTime.Now, result = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
return result.AddMinutes(((now.Minute / 60) + 1) * 60);
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
BackgroundJob.Schedule(() => StartRecurringJob(), RoundCurrentToNextOneHour());
return Task.CompletedTask;
}
public void StartRecurringJob()
{
RecurringJob.AddOrUpdate(() => DoWork(), Cron.Hourly, TimeZoneInfo.Local);
}
在这行代码中,您总是增加 60 分钟。
result.AddMinutes(((now.Minute / 60) + 1) * 60)
这是因为 Minute
属性 只能在值 0 到 59 之间,因此减少为:
result.AddMinutes((0 + 1) * 60)
result.AddMinutes(1 * 60)
result.AddMinutes(60)
试试这个:
result.AddMinutes((60 - (now.Minute % 60)) % 60)
例如,09:00
将显示为 09:00
,但 09:01
到 09:59
将四舍五入为 10:00
。听起来这就是您要求的行为。
您可能还想阅读 in the HangFire docs 关于 SchedulePollingInterval
的内容,这可能会影响您的结果。
使用 cron 表达式有更好的方法。如果您打开 https://crontab.guru 并尝试一些表达式,您会找到每个表达式的解释。
一些 cron 表达式的例子:
- 每 5 分钟:
0/5 * * * *
。
如果当前时间是 11:12 下午,它将在 11:15 下午执行一个方法,然后在 11:20 下午等。
- 每小时
0 * * * *
。
如果当前时间是11:12下午,它将在00:00上午、01:00上午、02:00上午等执行一个方法
除了cron 表达式之外,还有内置的cron 表达式。他们的源代码在这里:https://github.com/HangfireIO/Hangfire/blob/9cd09f38fa97e4c2dd48f6097985fd2b48b4568e/src/Hangfire.Core/Cron.cs#L231。如果我想每 1 小时做一些动作,那就是 Cron.Hourly()
.
示例代码如下:
RecurringJobManager manager = new RecurringJobManager();
manager.RemoveIfExists("myjob");
// Each 5 minutes, e.g. 01:05 pm, 01:10 pm, 01:15 pm, etc.
//manager.AddOrUpdate("myjob", Job.FromExpression(() => DoWork()), $"0/5 * * * *", TimeZoneInfo.Local);
// Each 1 hour, e.g. 01:00 pm, 02:00, 03:00 pm, etc.
manager.AddOrUpdate("myjob", Job.FromExpression(() => DoWork()), $"0 * * * *", TimeZoneInfo.Local);