【问题标题】:Using quartz-scheduler (cron) how to set an offset base time?使用石英调度程序(cron)如何设置偏移基准时间?
【发布时间】:2016-03-15 05:35:44
【问题描述】:

我正在尝试从某个时间点开始每隔 x 小时和 y 分钟运行一次的间隔任务。

目前我的 cron 看起来像这样。

    0 <OffsetMinsAmount>/<Mins Increment> <OffsetHoursAmount>/<Hours Increment> ? * *

    eg

    0 22/51 3/0 ? * * // starting at 3:22 every 51 mins do x

如果我在 3:22 之前安排上面的示例,它会在 3:22 运行,然后安排下一个运行时间 @ 4 22

这不是我所期望的,因为下一次应该是 4:13

根据我在网上阅读的内容,我做错了,因为这是一个小时内的 x 分钟。

谁能指出我做错了什么?

这也是我创建它的方式(.net):

    trigger = TriggerBuilder.Create()
                            .WithCronSchedule(cronExpression, x => x.WithMisfireHandlingInstructionDoNothing())
                            .StartAt(schedulerTask.Start.ToUniversalTime())
                            .EndAt(null)
                            .Build();

【问题讨论】:

  • 从它的声音看来,您更愿意使用简单的触发器?
  • 感谢@MarkoLahma 工作正常。如果你想写和回答不好点击解决:)
  • 嗯,为什么我的@MarkoLahma 没有工作..
  • 您自己的答案很好,很高兴您使用替代触发器类型解决了它。

标签: cron quartz.net


【解决方案1】:

这可能已经太晚了,但看起来您尝试使用的 cron 表达式实际上有 3 个问题。

既然您使用 repeatForever() 方法解决了您的问题,那么您可能不需要执行任何这些操作。我可以看到使用 SimpleSchedule 路线的唯一缺点是您失去了使用纯 cron 表达式所获得的一些灵活性(即,如果您想允许您的用户直接传递 cron 表达式,例如,或者如果您想支持其他不了解 Quartz 但熟悉 cron 表达式的系统)。这实际上取决于您使用它的用例。无论如何,这是解释:

说明

在分解表达式之前,需要了解有关 Quartz 的一件事是,每当您指定时间间隔时,间隔部分只会重复到特定时间值的限制(59 表示秒和分钟,23小时,31 天),而不会绕到下一分钟、一小时、一天等。如果(开始时间 + 间隔)超过了这个限制,就好像时间不存在(它真的不存在' t 如果您考虑一下),因此 Quartz 跳过它并继续下一个符合您日程安排的间隔,而不会超过。即使不指定时间间隔也是如此。

在您的示例22/51 中,您希望从22 分钟开始每隔51 分钟安排一次。但实际上最终发生的事情是,每次分钟标记达到22 时,您都安排了一些事情,而从未前往13。这是因为开始时间 + 间隔 (22 + 51 = 73) 超过了每分钟间隔的限制,即 59。 Quartz 不够聪明,不知道它应该“环绕”超过59 到下一小时的额外分钟。

这里还有一个问题,如果你指定了一个更小的时间间隔,比如10,那么你的表达式是22/10,那么你的计划将从@987654334分钟开始每隔10分钟执行一次@ 直到 59 的分钟限制。因此,如果您想从4:22 开始每隔10 分钟运行一次,那么它就不会像您预期的那样在4:02 和4:12 运行。同样,这是由于 Quartz 处理此问题的性质所致。

您应该做的是使用特殊范围字符- 指定您的分钟范围,这将告诉石英您希望它对超过最大值的任何分钟进行“换行”。所以你的分钟表达式实际上应该是22-21/51。这意味着从分钟 22 一直到分钟 21(换句话说,从 22-59 到 0-21 的整整一小时)你只想在这些组合分钟的每 51 分钟做一些事情.这实际上会让您超过59 分钟限制(或您使用的任何时间值)。

示例

官方Quartz documentation 实际上有一些例子说明了我要解释的内容。以下是一对:

0 0/5 14 * * ?     Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day

请注意,将 14(下午 2 点)指定为开始时间并不意味着它将每小时运行一次。这意味着时间表将从下午 2 点开始每 5 分钟运行一次,但永远不会超过下午 2 点到 3 点的范围。如果您想从下午 2 点开始每隔 5 分钟运行一次,每天每小时运行一次,那么表达式将是 0 0/5 14-13 * * ?(14-13 表示从小时数 14-23 转为小时数 0-13 以下天)

0 0/5 14,18 * * ?     Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day

这与上面的示例类似,除了从2-3pm 运行某些内容之外,他们还使用, 字符和小时值18 添加了另一个从6-7pm 开始的小时范围。

不幸的是,文档中的示例有点缺乏,并没有涵盖您在使用 Quartz 时可能遇到的所有不同组合和用例。 Cronmaker 是我发现对解决这些问题非常有用的一个工具,您可以使用它来验证您的 cron 表达式。

细分

以下是对示例 cron 表达式中错误的解释:

22/51

这是表达式的第一个问题。这意味着从 22 分钟开始每 51 分钟运行一次(例如 3:22),直到该小时的 59 分钟标记,但它不会像您期望的那样在 13 分钟标记处换行到下一个小时。请参阅上面的冗长解释。

3/0 

这是其他两个问题的所在。第一个是,类似于表达式的分钟部分,通过单独使用3,您可以说从第 3 小时开始运行,直到(但不包括)第 4 小时。第二个是通过使用/0 你实际上是在告诉它不要重复超过 3 次。

解决方案

要实现您希望从凌晨 3 点 22 分开始在每天的每个小时内每 51 分钟运行一次的计划,您应该使用以下命令:

0 22-21/51 3-2/1 * * ?

小时字段中的/1 实际上不是必需的,因为默认情况下它会每小时重复一次,但您可以保留它以明确显示这一点。因此,如果您愿意,可以将表达式简化为:

0 22-21/51 3-2 * * ?

请注意我如何指定分钟和小时的范围,以确保它们不会仅在特定限制结束前执行(59 分钟和 23 小时)。

无论如何,我希望这会有所帮助,如果我的解释有点混乱,我很抱歉。如果不亲自尝试,这有点难以描述并且可能理解这些东西。希望这些例子能让它更清楚一点。

【讨论】:

  • 不幸的是,我不再受雇于最初出现问题的同一家公司,所以我无法测试这个准确度是否修复了我的问题。无论如何,它对你来说是一个非常详细的解释道具:)。我相信这对任何遇到麻烦的人都会有用
【解决方案2】:

marko 先生在这里大赚一笔。

下面的工作很好,谢谢。

   int mins;
   if (int.TryParse(schedulerTask.Data, out mins) && mins > 0)
   {
       trigger = TriggerBuilder.Create()
           .WithSimpleSchedule(x => x
               .WithIntervalInMinutes(mins)
               .RepeatForever()
               .WithMisfireHandlingInstructionNextWithRemainingCount())
           .StartAt(schedulerTask.Start.ToUniversalTime())
           .EndAt(null)
           .Build();
   }

【讨论】:

    猜你喜欢
    • 2017-08-07
    • 1970-01-01
    • 2018-11-22
    • 2012-12-21
    • 1970-01-01
    • 2016-01-18
    • 2016-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多