【问题标题】:Scheduling Dependent Jobs in Quartz.Net在 Quartz.Net 中调度相关作业
【发布时间】:2011-10-09 18:21:58
【问题描述】:

我需要一些帮助。我试图弄清楚如何在 Quartz.Net 中安排作业。 Quartz 中的作业对应于我的 Web 应用程序中的任务,每个任务都是我的 Web 应用程序中作业的一部分。我希望用户能够按需启动作业(WebApplication 上下文)并使其立即运行或安排将来的作业,并且可能在给定的时间间隔内重复。我知道所有这些项目是如何在 Quartz 中单独完成的,但我很难把它们放在一起。

例如,在我的 Web 应用程序中,我的工作可能有多个任务,按特定顺序执行。我希望能够在石英中安排这些任务,以便它们以我的 Web 应用程序中确定的相同顺序执行。有人知道如何做到这一点吗?我已经阅读了 Quartz 文档,说要将下一个作业存储在 JobDataMap 中,只是在努力解决它。

我目前正在等待创建 Quartz 作业,直到用户请求调度作业或运行它。您是否认为我应该创建作业并在 Web 应用程序中创建任务时触发,然后从任务对象中提取该信息以在 Quartz 中进行调度?

【问题讨论】:

    标签: c# asp.net-mvc-3 quartz-scheduler quartz.net


    【解决方案1】:

    您需要的是 JobChainingJobListener 类,它可以帮助您按照您想要的特定顺序为您的作业创建一个执行链..

    using System;
    using System.Text;
    using Quartz;
    using Quartz.Impl;
    using Quartz.Impl.Calendar;
    using Quartz.Listener;
    using Quartz.Impl.Matchers;
    using System.Threading;
    
    namespace QuartzNET.Samples
    {
        class Program
        {
            static void Main(string[] args)
            {
                // Create RAMJobStore instance
                DirectSchedulerFactory.Instance.CreateVolatileScheduler(5);
                ISchedulerFactory factory = DirectSchedulerFactory.Instance;
    
                // Get scheduler and add object
                IScheduler scheduler = factory.GetScheduler();          
    
                StringBuilder history = new StringBuilder("Runtime History: ");
                scheduler.Context.Add("History", history);
    
                JobKey firstJobKey = JobKey.Create("FirstJob", "Pipeline");
                JobKey secondJobKey = JobKey.Create("SecondJob", "Pipeline");
                JobKey thirdJobKey = JobKey.Create("ThirdJob", "Pipeline"); 
    
                // Create job and trigger
                IJobDetail firstJob = JobBuilder.Create<FirstJob>()
                                           .WithIdentity(firstJobKey)
                                           //.StoreDurably(true)
                                           .Build();
    
                IJobDetail secondJob = JobBuilder.Create<SecondJob>()
                                           .WithIdentity(secondJobKey)                                       
                                           .StoreDurably(true)                                       
                                           .Build();
    
                IJobDetail thirdJob = JobBuilder.Create<ThirdJob>() 
                                           .WithIdentity(thirdJobKey)
                                           .StoreDurably(true)
                                           .Build();
    
                ITrigger firstJobTrigger = TriggerBuilder.Create()
                                                 .WithIdentity("Trigger", "Pipeline")
                                                 .WithSimpleSchedule(x => x
                                                     .WithMisfireHandlingInstructionFireNow()
                                                    .WithIntervalInSeconds(5)    
                                                    .RepeatForever())
                                                 .Build();
    
                JobChainingJobListener listener = new JobChainingJobListener("Pipeline Chain");
                listener.AddJobChainLink(firstJobKey, secondJobKey);
                listener.AddJobChainLink(secondJobKey, thirdJobKey);            
    
                scheduler.ListenerManager.AddJobListener(listener, GroupMatcher<JobKey>.GroupEquals("Pipeline"));
    
                // Run it all in chain
                scheduler.Start();
                scheduler.ScheduleJob(firstJob, firstJobTrigger);
                scheduler.AddJob(secondJob, false, true);
                scheduler.AddJob(thirdJob, false, true);
    
                Console.ReadLine();
                scheduler.Shutdown();
                Console.WriteLine("Scheduler shutdown.");
                Console.WriteLine(history);
                Console.ReadLine();
            }
        }
    
        class FirstJob : IJob
        {
            public void Execute(IJobExecutionContext context)
            {
                var history = context.Scheduler.Context["History"] as StringBuilder;
                history.AppendLine();
                history.AppendFormat("First {0}", DateTime.Now);            
                Console.WriteLine("First {0}", DateTime.Now);
            }
        }
    
        class SecondJob : IJob 
        {
            public void Execute(IJobExecutionContext context)
            {
                var history = context.Scheduler.Context["History"] as StringBuilder;
                history.AppendLine();
                history.AppendFormat("Second {0}", DateTime.Now);
                Console.WriteLine("Second {0}", DateTime.Now);            
            }
        }
    
        class ThirdJob : IJob
        {
            public void Execute(IJobExecutionContext context)
            {
                var history = context.Scheduler.Context["History"] as StringBuilder;
                history.AppendLine();
                history.AppendFormat("Third {0}", DateTime.Now);
                Console.WriteLine("Third {0}", DateTime.Now);
                Console.WriteLine();
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      关于第二段:如果我理解正确,您有一组作业,用户可以从中选择并按特定的执行顺序放置。我会通过创建用户选择的每个作业类型的作业实例来处理它。为了保持作业的顺序,可以将下一个作业的组名和作业名存储在上一个作业的 JobDataMap 中。然后你可以有一个通用的 JobListener,它注册了所有的作业。当作业执行时,侦听器将收到通知,并将作业包作为参数传递。 JobListener 可以枚举刚刚执行的作业的 JobDataMap。如果它找到键为“nextjobname”的键值对,JobListener 将查询调度程序以获取该作业。对作业包中的调度程序的引用。如果调度程序返回给定名称的 JobDetail 实例,JobListener 将执行它,并在完成时收到通知,依此类推,直到它到达 JobDataMap 中具有“nextjobname”的作业。
      或者,如果您不想拥有 Job Listeners,您可以拥有一个实现此功能的基本 Job 类。您的所有作业都将从此类派生,并将覆盖其虚拟 Execute 方法。您可以在重写实现返回之前调用 base.Execute(context) 。

      public class Basejob : IJob
      {
          public virtual void Execute(JobExecutionContext context)
          {
              string nextJob = context.MergedJobDataMap["nextjobname"];
              JobDetail nextjob = context.Scheduler.GetJobDetail(context.MergedJobDataMap["nextjobname"],
                                                 context.MergedJobDataMap["nextjobgroupname"]);
              if(nextjob != null)
              {
                  context.Scheduler.ScheduleJob(nextjob, new SimpleTrigger(nextjob.Name + "trigger")); // this will fire the job immediately
              }
          }
      }
      
      public class MyJob : BaseJob
      {
          public override void Execute(JobExecutionContext context)
          {
              //do work
              base.Execute(context);
          }
      }
      

      【讨论】:

      • 这是有道理的。您有任何 JobListener 或基本 Job 类的示例吗?
      • 另一个简单的问题:如何将触发器分配给通过侦听器执行的作业?据我了解,为了安排作业,您必须仅传递一个触发器(以及与之关联的作业)或触发器和作业。
      • 如果有人想知道,_scheduler.AddJob(JobDetail job, bool Replace) 允许您在没有关联触发器的情况下向数据存储添加作业... DUHHHHHHHHHHHHHHHHHH
      • 我知道我不太明白这个问题:)
      • 太棒了。你是一个巨大的帮助,让我克服了似乎无法移动的障碍。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2013-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      • 1970-01-01
      • 2021-05-28
      相关资源
      最近更新 更多