【问题标题】:Handling failures of chained jobs using Quartz.NET使用 Quartz.NET 处理链式作业的失败
【发布时间】:2015-10-27 23:07:35
【问题描述】:

我能够使用 Quartz.NET 安排 3 个链式作业。这个策略运行良好:

var j1 = new TestJob1();
var j2 = new TestJob2();
var j3 = new TestJob3();

var jd1 = j1.Build();
var jd2 = j2.Build();
var jd3 = j3.Build();


var chain = new JobChainingJobListener("jobchain");
chain.AddJobChainLink(jd1.Key, jd2.Key);
chain.AddJobChainLink(jd2.Key, jd3.Key);


Scheduler.ListenerManager.AddJobListener(chain, GroupMatcher<JobKey>.AnyGroup());

Scheduler.ScheduleJob(jd1, j1.JobTrigger());
Scheduler.AddJob(jd2, true);
Scheduler.AddJob(jd3, true);


Scheduler.Start();

每个作业的代码如下:

public class TestJob1 : BaseJob, IJob
    {
        public override ITrigger JobTrigger()
        {
             return TriggerBuilder.Create()
                 .WithSimpleSchedule(
                     ssb =>
                     ssb.WithInterval(new TimeSpan(0, 0, 0, 10)).RepeatForever().WithMisfireHandlingInstructionFireNow())
                 .Build();
        }

        public void Execute(IJobExecutionContext context)
        {
            Debug.WriteLine($"Running Job 1 at {DateTime.Now.ToString("O")}");
        }
    }

    public class TestJob2 : BaseJob, IJob
    {
        public override ITrigger JobTrigger()
        {
            throw new System.NotImplementedException();
        }

        public void Execute(IJobExecutionContext context)
        {
            Debug.WriteLine($"Running Job 2 at {DateTime.Now.ToString("O")}");
            throw new Exception("forced error");
        }
    }

    public class TestJob3 : BaseJob, IJob
    {
        public override ITrigger JobTrigger()
        {
            throw new System.NotImplementedException();
        }

        public void Execute(IJobExecutionContext context)
        {
            Debug.WriteLine($"Running Job 3 at {DateTime.Now.ToString("O")}");
        }
    }

如果您看到,TestJob2 在运行时抛出异常。即使在这种情况下,TestJob3 也会被触发。我的业务要求是,如果 TestJob2 失败,则不应触发 TestJob3。请注意,实际上我不需要为 job2 和 job3 实现触发器,因为我将那些没有触发器的作业添加到调度程序。

如何做到这一点?

提前致谢, 马里奥

【问题讨论】:

    标签: c# quartz.net


    【解决方案1】:

    子类JobChainingJobListener,并使用JobChainingJobListenerFailOnError 代替JobChainingJobListener

    /// <summary>
    /// JobChainingJobListener that doesn't run subsequent jobs when one fails.
    /// </summary>
    public class JobChainingJobListenerFailOnError : JobChainingJobListener
    {
        public JobChainingJobListenerFailOnError(String name) : base(name) { }
    
        public override void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
        {
            //Only call the base method if jobException is null.  Otherwise, an
            //error has occurred & we don't want to continue chaining
            if (jobException == null)
                base.JobWasExecuted(context, jobException);
        }
    }
    

    【讨论】:

      【解决方案2】:

      虽然 JobChain 对我来说是新的,但我仍然会使用基本的 clr api 调用并通过链接任务 (https://msdn.microsoft.com/en-us/library/ee372288(v=vs.110).aspx) 来利用任务并行库 (tpl)。

      这个特殊的代码将四个不同的任务链接在一起,如果没有前面的完成,一个任务就无法触发。我想要 Quartz 做的就是安排和打电话给我的工作。如果我偏离了quartz api,我深表歉意,但我只是想提供一种处理多项任务的方法。

      在我的工作中,我进入工作 Execute 并执行调用 Process()

      private async Task<Boolean> Process()
      {   
         Task<bool> t1 = Task<bool>.Factory.StartNew(() =>
         {
            return processThis();
         });
      
      
         Task<bool> t2 = t1.ContinueWith((ProcessMore) =>
         {
            return processMoreStuff();
         });
      
         Task<bool> t3 = t2.ContinueWith((ProcessEvenMore) =>
         {
            return processEvenMoreStuff();
         });
      
         Task<bool> t4 = t3.ContinueWith((ProcessStillSomeMore) =>
         {
            return processStillMoreStuff();
         });
      
      
          var result = await t4;
      
         try
         {
            Task.WaitAll(t1, t2, t3, t4);
         }
         catch (Exception ex)
         {
            System.Diagnostics.Trace.WriteLine(ex.Message);
         }
      
         return result;
      }
      

      【讨论】:

      • 你好@mg3。这是一个有趣的解决方案,但我将使用作业 API 等待答案,因为我已经有一些关于该样式的代码。如果使用 Quartz API 没有出现答案,我将转换为您建议的内容:)
      【解决方案3】:

      过去我不得不链接作业,但我没有使用 JobChainingJobListener。 我所做的是在第 (n) 个作业完成后添加并安排第 (n+1) 个作业。例如,当要执行的下一个作业取决于当前作业的结果时,这很有帮助,就像您的情况一样。

      要继续使用 JobChainingJobListener,我认为您可以在 TestJob2 成功结束时获取 TestJob3 并在其数据映射中设置一个标志。当 TestJob2 出现异常时,TestJob3 仍会执行,但您只需检查您的标志以查看它是否需要继续执行。

      【讨论】:

      • 这也是一个很好的解决方案,对数据库存储有好处。但这有点牵扯...我仍然会以更简单的方式使用 Quartz.net api 等待答案...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多