【问题标题】:Refire quartz.net trigger after 15 minutes if job fails with exception如果作业因异常而失败,则在 15 分钟后重新触发quartz.net 触发器
【发布时间】:2012-06-05 07:53:04
【问题描述】:

如果作业引发异常,我已经搜索了有关如何在一定时间后重新触发作业的答案。我看不到任何简单的方法。

如果我这样设置触发器:

JobDetail job = new JobDetail("Download catalog", null, typeof(MyJob));
job .Durable = true;
Trigger trigger= TriggerUtils.MakeDailyTrigger(12, 0);
trigger.StartTimeUtc = DateTime.UtcNow;
trigger.Name = "trigger name";
scheduler.ScheduleJob(job , trigger);

MyJob 看起来像这样:

public class MyJob : IJob
{
    public void Execute(JobExecutionContext context)
    {
        var service = new service();


        try
        {
            service.Download();
        }
        catch (Exception)
        {
            throw;
        }

    }
}

如果 service.Download() 调用引发某种异常,我如何在 15 分钟后重新触发/重新触发?

【问题讨论】:

    标签: triggers quartz.net


    【解决方案1】:

    实际上,没有必要像 LeftyX 描述的那样创建一个新的 JobDetail。您可以只安排一个从当前上下文连接到 JobDetail 的新触发器。

    public void Execute(JobExecutionContext context) {
        try {
            // code
        } catch (Exception ex) {
            SimpleTriggerImpl retryTrigger = new SimpleTriggerImpl(Guid.NewGuid().ToString());      
            retryTrigger.Description = "RetryTrigger";
            retryTrigger.RepeatCount = 0;
            retryTrigger.JobKey = context.JobDetail.Key;   // connect trigger with current job      
            retryTrigger.StartTimeUtc = DateBuilder.NextGivenSecondDate(DateTime.Now, 30);  // Execute after 30 seconds from now
            context.Scheduler.ScheduleJob(retryTrigger);   // schedule the trigger
    
            JobExecutionException jex = new JobExecutionException(ex, false);
            throw jex;
        }
    }
    

    这比创建新的 JobDetail 更不容易出错。希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      我认为正确的答案是使用 JobListener 重试作业,如下所述:http://thecodesaysitall.blogspot.cz/2012/03/quartz-candy-part-1.html

      您在此解决方案中将重试逻辑与 Job 本身分开,因此可以重复使用。

      如果您按照此处其他回复中的建议在作业中实施重试逻辑,则必须在每个作业中再次实施。

      编辑: 根据 Ramanpreet Singh 的说明,可以找到更好的解决方案 herehttps://blog.harveydelaney.com/quartz-job-exception-retrying/

      【讨论】:

      • 我同意。公认的答案是“安全带和大括号”解决方案(如果您只需要完成工作,这很好),但添加“重试侦听器”可能是一个更好(并且更可重用)的长期解决方案。我不认为实现是完美的,但它是一个很好的起点...... GitHub上的来源:github.com/malmgren80/Quartz.Candy
      • 链接的解决方案在这里得到了改进:blog.harveydelaney.com/quartz-job-exception-retrying
      • @DavidKirkland 您的解决方案非常棒。干净整洁
      【解决方案3】:

      我认为您唯一的选择是捕获错误并告诉 Quartz.net 立即重新启动:

      public class MyJob : IJob
      {
          public void Execute(JobExecutionContext context)
          {
              var service = new service();
      
              try
              {
                  service.Download();
              }
              catch (Exception ex)
              {
                    JobExecutionException qe = new JobExecutionException(ex);
                    qe.RefireImmediately = true;  // this job will refire immediately
                    throw qe;  
              }
          }
      }
      

      您可以找到一些信息herehere

      更新

      我做了一些测试,您似乎可以在正在执行的作业中安排一个新的触发器。
      你可以试试这样的:

      public class MyJob : IJob
      {
          public void Execute(JobExecutionContext context)
          {
              var service = new service();
      
              try
              {
                  service.Download();
              }
              catch (Exception ex)
              {
                  JobExecutionException qe = new JobExecutionException(ex);
                  // qe.RefireImmediately = true;  // this job will refire immediately
                  // throw qe;  
                  OnErrorScheduleJob(context);
      
              }
          }
      
          private void OnErrorScheduleJob(JobExecutionContext context)
          {
              var jobOnError = context.Scheduler.GetJobDetail("ONERRORJOB", "ERROR");
              if (jobOnError == null)
              {
              JobDetail job = new JobDetail("ONERRORJOB", "ERROR", typeof(MyJob));
              job.Durable = false;
              job.Volatile = false;
              job.RequestsRecovery = false;
      
              SimpleTrigger trigger = new SimpleTrigger("ONERRORTRIGGER",
                              "ERROR",
                              DateTime.UtcNow.AddMinutes(15),
                              null,
                              1,
                              TimeSpan.FromMinutes(100));
      
              context.Scheduler.ScheduleJob(job, trigger);     
              }
          }
      }
      

      【讨论】:

      • 是的。这是我读过的,但这不是一个好的解决方案,因为它可能意味着它会重新触发数千次(甚至重新触发数百万次)。但很高兴看到您得出了这个结论。
      • 谢谢:D 我也有同样的想法,但这是我第一次使用石英,所以我不确定你是否可以使用上下文。
      • @mslot:没问题。很高兴我能帮上忙。
      【解决方案4】:
      // don't forget to use @PersistJobDataAfterExecution without it, the jobExecutionContext will reset the value of count.     
      
      SimpleTriggerImpl retryTrigger = new SimpleTriggerImpl();
          retryTrigger.setName("jobname");
          retryTrigger.setRepeatCount(0);
          retryTrigger.setJobKey(jobExecutionContext.getJobDetail().getKey());
          final Calendar cal = getCalendarInstance();
          cal.add(Calendar.MINUTE, 1); //retry after one minute
          retryTrigger.setStartTime(cal.getTime());
          try {
              jobExecutionContext.getScheduler().scheduleJob(retryTrigger);   // schedule the trigger
          } catch (SchedulerException ex) {
              logger.error("something went wrong", ex); 
          }
          JobExecutionException e2 = new JobExecutionException("retrying...");
          e2.refireImmediately();
          throw e2;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多