2016-07-25 31 views
2

我已經加入對作業的屬性DisableConcurrentExecution(1),但這一切確實是延誤工作的第二個實例的執行,直到第一個完成之後。我希望能夠檢測到並行作業何時運行,然後一起取消它。如何取消同時運行兩次的重複作業?

我想,如果DisableConcurrentExecution(1)會阻止同一經常作業的兩個實例同時運行,它會將第二個作業放在「重試」上,從而改變它的狀態。

public class StopConcurrentTask : JobFilterAttribute, IElectStateFilter 
{ 
    public void OnStateElection(ElectStateContext context) 
    { 
     var failedState = context.CandidateState as FailedState; 
     if(failedState != null && failedState.Exception != null) 
     { 
      if(!string.IsNullOrEmpty(failedState.Exception.Message) && failedState.Exception.Message.Contains("Timeout expired. The timeout elapsed prior to obtaining a distributed lock on")) 
      { 

      } 
     } 
    } 
} 

這讓我來檢測作業是否失敗,原因是正在與同一作業的另一個實例同時運行:所以我在工作中,它可以檢測失敗的國家,像這樣增加了額外的自定義屬性。問題是,我無法找到一種方法來取消這個特定的失敗作業,並將其從重新運行中刪除。就像現在這樣,這份工作將被放在重試計劃上,Hangfire會嘗試多次運行它。

我當然可以提上工作的屬性,以確保它不會重試的。但是,這不是一個有效的解決方案,因爲我希望作業能夠被重做,除非由於同時運行而失敗。

+0

你能澄清你的兩個段落。對不起,但我有點困惑。 – jtabuloc

回答

3

您可以防止重試,如果你把驗證在OnPerformed方法IServerFilter界面發生。

實現:

public class StopConcurrentTask : JobFilterAttribute, IElectStateFilter, IServerFilter 
    { 
     // All failed after retry will be catched here and I don't know if you still need this 
     // but it is up to you 
     public void OnStateElection(ElectStateContext context) 
     { 
      var failedState = context.CandidateState as FailedState; 
      if (failedState != null && failedState.Exception != null) 
      { 
       if (!string.IsNullOrEmpty(failedState.Exception.Message) && failedState.Exception.Message.Contains("Timeout expired. The timeout elapsed prior to obtaining a distributed lock on")) 
       { 

       } 
      } 
     } 

     public void OnPerformed(PerformedContext filterContext) 
     { 
      // Do your exception handling or validation here 
      if (filterContext.Exception == null) return; 

      using (var connection = _jobStorage.GetConnection()) 
      { 
       var storageConnection = connection as JobStorageConnection; 

       if (storageConnection == null) 
        return; 

       var jobId = filterContext.BackgroundJob.Id 
       // var job = storageConnection.GetJobData(jobId); -- If you want job detail 

       var failedState = new FailedState(filterContext.Exception) 
       { 
        Reason = "Your Exception Message or filterContext.Exception.Message" 
       }; 

       using (var transaction = connection.GetConnection().CreateWriteTransaction()) 
       { 
        transaction.RemoveFromSet("retries", jobId); // Remove from retry state 
        transaction.RemoveFromSet("schedule", jobId); // Remove from schedule state 
        transaction.SetJobState(jobId, failedState); // update status with failed state 
        transaction.Commit(); 
       } 
      } 
     } 

     public void OnPerforming(PerformingContext filterContext) 
     { 
      // Do nothing 
     } 
    } 

我希望這會幫助你。

0

其實,我結束了使用基於JR Tabuloc答案 - 它會刪除工作,如果它已經過去15秒前執行 - 我注意到服務器喚醒和作業執行變化之間的時間。它通常以毫秒爲單位,但因爲我的作業每天執行一次,我想15秒也不會受到傷害。

public class StopWakeUpExecution : JobFilterAttribute, IServerFilter 
{ 
    public void OnPerformed(PerformedContext filterContext) 
    { 

    } 

    public void OnPerforming(PerformingContext filterContext) 
    { 
     using (var connection = JobStorage.Current.GetConnection()) 
     { 
      var recurring = connection.GetRecurringJobs().FirstOrDefault(p => p.Job.ToString() == filterContext.BackgroundJob.Job.ToString()); 
      TimeSpan difference = DateTime.UtcNow.Subtract(recurring.LastExecution.Value); 
      if (recurring != null && difference.Seconds < 15) 
      { 
       // Execution was due in the past. We don't want to automaticly execute jobs after server crash though. 

       var storageConnection = connection as JobStorageConnection; 

       if (storageConnection == null) 
        return; 

       var jobId = filterContext.BackgroundJob.Id; 

       var deletedState = new DeletedState() 
       { 
        Reason = "Task was due in the past. Please Execute manually if required." 
       }; 

       using (var transaction = connection.CreateWriteTransaction()) 
       { 
        transaction.RemoveFromSet("retries", jobId); // Remove from retry state 
        transaction.RemoveFromSet("schedule", jobId); // Remove from schedule state 
        transaction.SetJobState(jobId, deletedState); // update status with failed state 
        transaction.Commit(); 
       } 
      } 
     } 
    } 
} 
相關問題