在Quartz.Net中调度依赖作业

时间:2011-07-20 21:13:49

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

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

例如,在我的Web应用程序中,我可能按照特定顺序拥有多项任务。我希望能够在quartz中安排这些任务,以便它们以我的Web应用程序中确定的相同顺序执行。有人知道怎么做吗?我已阅读Quartz文档,说要将下一个Job存储在JobDataMap中,只是在努力解决它。

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

2 个答案:

答案 0 :(得分:11)

你需要的是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();
        }
    }
}

答案 1 :(得分:4)

在第二段:如果我理解正确,你有一组工作,用户可以从中选择并按照特定的执行顺序。我会通过创建用户选择的每种作业类型的作业实例来接近它。为了保持作业的顺序,您可以将下一个作业的组名和作业名存储在上一个作业的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);
    }
}