2017-04-17 113 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實例。 –