Quart.Net默认只使用作业的优先级,如果它与另一个作业同时被触发。但是,如果在不同的时间触发了两个作业,则最早的作业将始终首先在线程池上运行。我有一个场景,但我需要队列中的最高优先级作业始终在下一个线程上运行。有没有一种简单的方法可以使用Quartz.Net执行此操作,或者如果我想完成此操作,我是否必须实现自己的调度程序? (或转向其他技术)。
我想到的具体方案: 定期作业将以高优先级触发,可能会为另一个过程产生一些输出。最大限度地减少等待时间非常重要。但是,我也有时会以较低的优先级同时触发多达数千个工作批次。我担心当这些“批次”被触发时,更重要的工作将等待太长时间才能运行。
有一种简单的方法可以使用Quartz.Net或竞争技术吗?
答案 0 :(得分:0)
您是否看过触发优先级?我不认为它会在不同的线程上运行它,但它会推动作业在另一个以较低优先级触发的作业之前启动。
Trigger trigger = TriggerBuilder.Create()
.WithIdentity("TestTrigger")
.StartNow()
.WithPriority(10)
.Build();
答案 1 :(得分:0)
如您所述,Quartz.Net并未直接支持此功能。您可以创建自己的调度程序(参见下文),或者如果您通过更新QRTZ_TRIGGERS表中的NEXT_FIRE_TIME列来使用数据库存储,则可以解决此问题。如果更新NEXT_FIRE_TIME以便按优先级排序它们,则下次调度程序检查计划更改时,将按优先级顺序执行作业。
有一个
public void SignalSchedulingChange(DateTimeOffset? candidateNewNextFireTimeUtc)
更新火灾时间后您可以调用的QuartzScheduler上的方法,但不幸的是StdScheduler没有公开。如果你正在沿着“我自己的调度程序”路线走下去,你可以直接调用它。否则,在调度程序上调用ScheduleJob方法(以及调度作业)也会调用它,因此您可以在更新下一次触发时间后利用它并安排作业。
答案 2 :(得分:0)
实现此行为的最简单方法是继承StdAdoDelegate
(或其中一个特定于数据库的实现)并覆盖GetSelectNextTriggerToAcquireSql
,以便在PRIORITY
之前按NEXT_FIRE_TIME
进行排序代替。
以下类获取默认SQL查询,并在临时空字符占位符的帮助下按子句交换顺序:
public class CustomAdoDelegate : StdAdoDelegate
{
protected override string GetSelectNextTriggerToAcquireSql(int maxCount)
{
return base.GetSelectNextTriggerToAcquireSql(maxCount)
.Replace(ColumnNextFireTime + " ASC", "\0")
.Replace(ColumnPriority + " DESC", ColumnNextFireTime + " ASC")
.Replace("\0", ColumnPriority + " DESC");
}
}
请记住,如果调度程序被更高优先级的作业所淹没,这可能会导致较低优先级作业的长时间延迟。
我自己没有尝试过,但可能值得考虑采用某种混合方式来平衡PRIORITY
和NEXT_FIRE_TIME
值。例如,您可以从下一个触发时间中以秒为单位减去优先级,以创建一种可变大小的优先级窗口。
order by dateadd(ss, -PRIORITY, NEXT_FIRE_TIME)
因此,优先级= 10的触发器只会在5秒后触发优先级= 5的触发器。只是一个想法。