我有一项每X分钟运行一次的服务。如果由于某些不可预见的原因,该作业的耗时超过X分钟,我想确保触发器不会启动此作业的第二个实例。
示例场景
有没有办法将Quartz.NET连接到只允许1个Job的实例?我可以使用第二个触发器等待第一个触发完成,或者我也可以选择跳过第二个触发器,因为它会在一分钟内再次触发。
我查看了Quartz API的Java版本,发现了一个属性“DisallowConcurrentExecution”,但在.NET版本中找不到类似的东西。
我的Quartz.NET实现代码
public IScheduler Scheduler { get; set; }
public IJobListener AutofacJobListener { get; set; }
public void Start()
{
var trigger = TriggerUtils.MakeMinutelyTrigger(1);
trigger.Name = @"Document Import Trigger";
Scheduler.ScheduleJob(new JobDetail("Document Import", null, typeof(DocumentImportJob)), trigger);
Scheduler.AddGlobalJobListener(AutofacJobListener);
Scheduler.Start();
}
答案 0 :(得分:50)
使用DisallowConcurrentExecution属性。
按如下方式声明您的课程:
[DisallowConcurrentExecution]
public class SomeTask : IJob
{
}
<强>失火强>
“失火说明”触发器的另一个重要特性是它 “失火指令”。如果持续触发,则会发生失火 由于调度程序被关闭,“错过”其启动时间,或 因为Quartz.NET的线程池中没有可用的线程 执行工作。不同的触发类型有不同的失火 他们可以获得的指示。默认情况下,他们使用“智能政策” 指令 - 具有基于触发类型和动态行为的动态行为 组态。当调度程序启动时,它会搜索任何调度程序 持有失败的持久性触发器,然后更新每个触发器 它们基于各自配置的失火指令。什么时候 你开始在你自己的项目中使用Quartz.NET 你自己熟悉定义的失火指令 给定的触发器类型,并在其API文档中进行了解释。 将提供有关失火指令的更多具体信息 在每个触发器类型特定的教程课程中。“
查看这些页面底部的“触发失火说明”信息:
旧的Quartz.NET API回答:
http://quartznet.sourceforge.net/apidoc/topic142.html:
IStatefulJob 实例遵循与常规规则略有不同的规则 IJob实例。关键的区别是 他们关联的JobDataMap是 每次执行后都会重新坚持下去 这项工作,因此保留了国家 下次执行。另一个区别 是有条不紊的工作是不允许的 同时执行,这意味着 在之前发生的新触发器 完成IJob.Execute方法 将被推迟。
所以,按如下方式声明你的'Job'类:
class DocumentImportJob : IStatefulJob
{
......
}
为避免延迟任务在作业完成后立即重新启动(当作业超过1分钟并导致触发'失火'时),请在创建触发器时执行以下操作(根据使用的触发类型进行调整) ):
myJobTrigger.MisfireInstruction = MisfireInstruction.CronTrigger.DoNothing;
https://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/more-about-triggers.html
答案 1 :(得分:44)
作为对此答案的更新,在较新版本的Quartz.Net中,现在通过属性&#34; DisallowConcurrentExecution&#34;你申请工作:
[DisallowConcurrentExecution]
public class MyJob : IJob
{
..
}
对于失火指令,这是如何做到的:
var trigger = TriggerBuilder.Create()
.WithSimpleSchedule(ssb => ssb.WithIntervalInMinutes(interval)
.RepeatForever()
.WithMisfireHandlingInstructionIgnoreMisfires()
)
.Build();
答案 2 :(得分:4)
嗯,一个简单的方法是将标志值存储在某处的变量中,并在进入作业方法时检查变量。
这样你就可以让工作第二次“开始”,它会在没有做任何实际工作的情况下立即退出。
以下是一个例子:
private volatile bool _IsRunning;
...
if (Interlocked.Exchange(ref _IsRunning, true))
return;
try
{
// job code
}
finally
{
_IsRunning = false;
}
答案 3 :(得分:-5)
public bool Validar(IJobExecutionContext context) {
if (context.Scheduler.GetCurrentlyExecutingJobs().Any(x => x.FireInstanceId != context.FireInstanceId
&& x.JobDetail.Key == context.JobDetail.Key))
{
return true;
}
else
{
return false;
}
}