开发者

Scheduling Dependent Jobs in Quartz.Net

I need some help. I am trying to figure out how to schedule jobs in Quartz.Net. Jobs in Quartz correspond to tasks in my Web Application, which are each apart of a Job in my Web Application. I want users to be able to launch a Job (WebApplication Context) on demand and have it run immediately or schedule the job in the future and, to possibly repeat on a given interval. I know how all these items are accomplished in Quartz individually, but i am having a hard time putting it all together.

For example, in my web application, I may have a job with several task, in a specific order. I want to be abl开发者_JS百科e to schedule these tasks in quartz so that they execute in the same order determined in my Web Application. Does anybody have idea of how to do this? I have read up on Quartz documentation saying to store the next Job in the JobDataMap, Just struggling with it.

I am currently waiting to create Quartz jobs until a user requests to either schedule the Job or Run it. Do you think I should be creating the job and trigger on creation of the task in the Web App and then pulling that information from the task object for scheduling in Quartz?


What you need is the JobChainingJobListener class, which is there to help you create a chain of execution for your jobs in a specific order you desire..

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();
        }
    }
}


On the second paragraph: If I understand you correctly, you have a set of jobs, from which the user can select and put in certain order of execution. I would approach it by creating a job instance of every job type selected by the user. In order to persist the order of the jobs, you can store the groupname and jobname of the next job in the JobDataMap of the previous job. Then you can have a generic JobListener, which is registered with all jobs. The listener will get notified when a job is executed and will be passed the job bundle as an argument. The JobListener can enumerate the JobDataMap of the job which has just been executed. If it finds a key-value pair with key "nextjobname", the JobListener will query the scheduler for this job. A reference to the scheduler of also available in the job bundle. If the scheduler returns an instance of JobDetail for the given name, the JobListener will execute it, will get notified when it completes and so on until it gets to a job with "nextjobname" in the JobDataMap.
Alternatively, if you don't want to have Job Listeners, you can have a base Job class which implements this functionality.All your jobs will derive from this class and will override its virtual Execute method. You can call base.Execute(context) just before the overriding implementation returns.

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);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜