Hangfire定时任务每分钟以下的重复任务

47

有没有一种方法可以每隔几秒钟设置Hangfire重复任务? 我不想使用“Fire and Forget”任务创建另一个“Fire and Forget”任务的解决方案,如果没有,有什么建议的替代方案?


关于此文档,似乎不可能按秒创建重复任务。最小单位是分钟 - ckruczek
7个回答

66

不确定这是从什么时候开始支持的,但我在ASP.NET Core 2.0中尝试了使用Hangfire 1.7.0。以下代码将每20秒安排一个作业:

RecurringJob.AddOrUpdate<SomeJob>(
    x => x.DoWork(),
    "*/20 * * * * *");

如果我没记错的话,由于Hangfire使用了NCrontab,支持6个令牌(而不是标准的5个令牌),它允许使用具有6个令牌的cron表达式(以秒为粒度而不是分钟)。

Hangfire仪表板还很好地显示了运行之间的小时间间隔:

Hangfire dashboard


9
如果您需要运行少于15秒,请设置 SchedulePollingInterval,就像 takaz 指出的那样。 - JohnnyFun
3
看起来这是在1.7或更高版本中添加的。太棒了!! - Glebby

31
我认为任何反对允许小于1分钟的重复触发的人都是短视的。毕竟,55秒是否比1分钟更有效?这似乎很武断!尽管我非常喜欢Hangfire,但我遇到过情况,不得不引导客户使用Quartz.net,只因为业务要求定时作业每55秒或类似时间运行。
任何人提出反驳意见说如果配置为1秒运行一次会严重影响性能,那么他们又在从一个封闭的视角看待问题。当然,1秒间隔的触发器可能不是一个好主意,但我们是否禁止55秒或45秒,只是为了防范极少数人会选择1秒的情况?
无论如何,性能是主观的,也取决于主机平台和硬件。当涉及性能问题时,API强制执行意见并不合适。只需使轮询间隔和触发器重复可配置即可。这样用户就可以自己确定最佳结果。
虽然编排每55秒运行作业的后台进程可能是一种选择,但它并不是很令人满意。在这种情况下,该进程在Hangfire UI中不可见,因此管理员无法看到它。我认为这种方法绕过了Hangfire的主要优点之一。
如果Hangfire是Quartz.net等竞争对手的严肃竞争者,它至少应该匹配其基本功能。如果Quartz可以支持小于1分钟的触发器,那么为什么Hangfire不能呢!

这是非常正确的。这就是为什么他们引入了第二级粒度的原因:https://dev59.com/-VoT5IYBdhLWcg3wnQj9#40598098 - Alexei - check Codidact

16

虽然Hangfire不允许您为少于一分钟的任务安排计划,但实际上您可以通过使函数递归调用自身来实现这一点;也就是说,假设您希望某个方法每2秒被调用一次,您可以安排一个后台作业,在启动时调用该方法。

BackgroundJob.Schedule(() => PublishMessage(), TimeSpan.FromMilliseconds(2000));

然后在您的PublishMessage方法中完成您的操作,然后安排一个作业来调用相同的方法;

public void PublishMessage()
    {
        /* do your stuff */

        //then schedule a job to exec the same method
        BackgroundJob.Schedule(() => PublishMessage(), TimeSpan.FromMilliseconds(2000));
    }

另外一个需要覆盖的是默认的SchedulePollingInterval,它是15秒。否则,你的方法只会每隔15秒运行一次。为了这样做,只需在启动时将BackgroundJobServerOptions的实例传递给UseHangfireServer,像这样:

var options = new BackgroundJobServerOptions
        {
            SchedulePollingInterval = TimeSpan.FromMilliseconds(2000)
        };

        app.UseHangfireServer(options);

我不知道我的解决方案有多么“万无一失”,但是我用它达到了我的目标,生产中的一切都很“顺利”。


问题中已经说明不希望创建其他任务的任务作为答案。我猜这是出于设计上的考虑,就是这样。 - Robert

9

我也需要做同样的事情,但是要求在5秒内完成。默认的调度轮询间隔设置为15秒。因此,需要进行2步操作才能实现5秒间隔的工作。

在Startup.cs文件中

var options = new BackgroundJobServerOptions
{
    SchedulePollingInterval = TimeSpan.FromMilliseconds(5000)
};

app.UseHangfireDashboard();
app.UseHangfireServer(options);

您的工作

RecurringJob.AddOrUpdate(() => YourJob(), "*/5 * * * * *");

4

Hangfire不支持小于一分钟的定期作业间隔。

为什么?想象一下,如果他们允许小于一分钟:比如1秒。那么Hangfire会多频繁地检查数据库中的定期作业呢?这将导致大量的数据库IO。

有关更多信息,请参见Hangfire上的此讨论


5
那么这个数据库或 Redis 是如何处理数百个“发送并忘记”任务的?它们肯定在一分钟内完成。 - Robert
请查看此链接,了解我的意思 :) - https://discuss.hangfire.io/t/recurring-job-every-seconds/877 - jtabuloc
1
@jtabuloc - 这已经不再是真的了 - 请看下面我的回答:https://dev59.com/-VoT5IYBdhLWcg3wnQj9#40598098。另外,如果我被要求每30秒运行一次短程序(实际上在一个项目中需要这样做),该怎么办? - Alexei - check Codidact
我还需要每15或30秒的定时任务。 - Zapnologica

0
我有一个类似的需求,即需要每15秒运行一次重复的作业。 为了尝试绕过这个限制,我延迟了计划作业的创建(设置为1分钟间隔),这似乎起到了作用。 然而,我发现,考虑到轮询间隔(将schedulepolling间隔设置为我的频率)和延迟接收新作业,这并不总是像应该的那样准确,但目前还可以应付。然而,更好/适当的解决方案会更好。 感觉有点不好意思,不得不采取以下方法,但它帮助了我... 因此,本质上我创建了4个执行相同任务的作业,相隔15秒创建一个。

...

new Thread(() =>
{
    //loop from {id=1 through 4}
    //   create job here with {id} in the name at interval of 1 minute
    //   sleep 15 seconds
    //end loop
}).Start();    
...

0

我也遇到了同样的问题,这是我的解决方案:

private void TimingExecuteWrapper(Action action, int sleepSeconds, int intervalSeconds)
{
    DateTime beginTime = DateTime.UtcNow, endTime;
    var interval = TimeSpan.FromSeconds(intervalSeconds);
    while (true)
    {
        action();
        Thread.Sleep(TimeSpan.FromSeconds(sleepSeconds));
        endTime = DateTime.UtcNow;
        if (endTime - beginTime >= interval)
            break;
    }
}

intervalSeconds 是最小的 NCRON 时间间隔。它是1分钟。 action 是我们的工作代码。 此外,我建议使用 DisableConcurrentExecution 来避免一些并发冲突。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接