2016-07-25 153 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(); 
       } 
      } 
     } 
    } 
} 
相关问题