2017-04-17 89 views
1

我提到了以下问题,但没有帮我解决问题。在Quartz.net中,一次运行一个作业的一个实例

In Quartz.NET is there a way to set a property that will only allow one instance of a Job to run?

https://github.com/quartznet/quartznet/issues/469

对于CronTrigger,用于调度cs.WithMisfireHandlingInstructionDoNothing()以下。

将以下属性应用于HelloJob
DisallowConcurrentExecution

代码发生了什么?
在Execute方法中,我设置了重点。基于我的代码,execute方法将在10秒内执行。

打到第一个突破点后,我又等了31秒。然后根据我的预期,我已经移除了突破点并执行了代码,应该只执行一次另一次尝试。

但执行方法在另一个 10秒内执行3次(3 * 10秒)。

如何解决这个问题?

调度程序代码。

ISchedulerFactory schedFact = new StdSchedulerFactory(); 
IScheduler sched = schedFact.GetScheduler(); 
sched.Start(); 

// define the job and tie it to our HelloJob class 
IJobDetail job = JobBuilder.Create<HelloJob>() 
    .WithIdentity("myJob", "group1") 
    .Build(); 

// Trigger the job to run now, and then every 40 seconds 
ITrigger trigger = trigger = TriggerBuilder.Create() 
    .WithIdentity("trigger3", "group1") 
    .WithCronSchedule("0/10 * * * * ?",cs=>cs.WithMisfireHandlingInstructionDoNothing()) 
    .ForJob("myJob", "group1") 
    .Build(); 

TriggerKey key = new TriggerKey("trigger3", "group1"); 
sched.ScheduleJob(job, trigger); 

作业执行代码。

[DisallowConcurrentExecution] 
public class HelloJob : IJob 
{   
    public static int count = 1; 
    public void Execute(IJobExecutionContext context) 
    { 
     Console.WriteLine(count+" HelloJob strted On." + DateTime.Now.ToString()); 
     if (count == 1) 
      Thread.Sleep(TimeSpan.FromSeconds(30)); 

     Interlocked.Increment(ref count); 
    } 
} 

enter image description here

====================================== ==============================

解决方案

没有必要去为互锁或手工管理。

石英已经被设计成只有完成第一个时间表,下一个开始。

所以我们不必担心它会同时运行。

例如(像我这样的人:-p),调度程序安排了10分钟。

但是,如果我们在执行方法中复制以下代码,则可以看到, 第一次完成需要20分钟。 第二次完成需要15分钟。

在10分钟之后不会有下一个计划开始。

var startTime = DateTime.UtcNow; 

      if (count == 1) 
      { 
       while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(20)) 
       { 
        // Execute your loop here... 
       } 
      } 
      else if (count > 1) 
      { 
       while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(15)) 
       { 
        // Execute your loop here... 
       } 
      } 
      count++; 
+0

您是否尝试过在没有附加调试器的情况下执行?只写日志?也许调试器会影响行为。 –

+0

我想运行超过10秒的执行。所以我试着用调试器。 –

+0

无论如何,尝试使用'Thread.Sleep'来代替调试器来确认问题。调试器会影响执行。 –

回答

2

发生在你身上的情况是,在第一个长30秒内执行作业Quartz会计划执行另外三次执行。这就是为什么在长时间执行之后,看到三次短暂的执行。他们是而不是在同一时间执行。一个接一个,但毫不拖延。那就是如何设计Quartz

[DisallowConcurrentExecution] 
public class HelloJob : IJob 
{ 
    public static int count = 1; 
    public void Execute(IJobExecutionContext context) 
    { 
     Console.WriteLine("HelloJob strted On." + DateTime.UtcNow.Ticks); 
     if (count == 1) 
      Thread.Sleep(TimeSpan.FromSeconds(30)); 

     Interlocked.Increment(ref count); 
    } 
} 

和输出:

Ctrl+C to exit. 
HelloJob strted On.636280218500144776 
HelloJob strted On.636280218800201691 
HelloJob strted On.636280218800211705 
HelloJob strted On.636280218800222083 
HelloJob strted On.636280218900009629 
HelloJob strted On.636280219000000490 

见,时间戳是第一个完成后不同,下次启动。

如果你想避免这种行为,你应该增加作业之间的延迟,或者@BrunoFerreira建议手动处理这个作业的时间表。

+0

没有这样写就像总是线程睡30秒。检查我更新的hellojob类。第一次,它将运行30秒,对于随后的呼叫,它将运行10秒。 30秒后,它会在10秒内连续运行3次 –

+0

检查我的hellojob –

+0

@JeevaJsb,请检查我的更新答案。 –

1

我前几天面对同样的问题。转过来,我不得不不计划工作,这是触发。 我在应用程序结束时使用此方法来执行此操作。

private void StopAllJobs() 
{ 
    // construct a scheduler factory 
    ISchedulerFactory schedFact = new StdSchedulerFactory(); 
    // get a scheduler, start the schedular before triggers or anything else 
    sched = schedFact.GetScheduler(); 
    var executingJobs = sched.GetCurrentlyExecutingJobs(); 
    foreach (var job in executingJobs) 
    { 
     sched.Interrupt(job.JobDetail.Key); 
     sched.UnscheduleJob(job.Trigger.Key); 
     sched.DeleteJob(job.JobDetail.Key); 
    } 
    sched.Clear(); 
} 

希望这可以帮助你。

+0

我不明白你的流量。何时不计划我的所有工作,为什么?如果我不再安排时间表再次开始? –

+0

不,您必须在应用程序结束时取消计划。就我而言,我使用Windows服务中的工作,所以当服务停止时,我不得不调度工作。如果我不这样做,下一次服务明星,我有两倍的工作runnig实例。 –