Планирование зависимых заданий в Quartz.Net - PullRequest
5 голосов
/ 21 июля 2011

Мне нужна помощь.Я пытаюсь выяснить, как планировать работу в Quartz.Net.Задания в Quartz соответствуют задачам в моем веб-приложении, каждая из которых является частью задания в моем веб-приложении.Я хочу, чтобы пользователи могли запускать задание (контекст WebApplication) по требованию и запускать его немедленно или планировать задание на будущее и, возможно, повторять через определенный интервал.Я знаю, как все эти элементы выполняются в Кварце индивидуально, но мне трудно все это собрать.

Например, в моем веб-приложении у меня может быть работа с несколькими задачами в определенном порядке.Я хочу иметь возможность планировать эти задачи в кварце, чтобы они выполнялись в том же порядке, который указан в моем веб-приложении.У кого-нибудь есть идеи, как это сделать?Я прочитал документацию по Quartz, в которой говорится о сохранении следующего задания в JobDataMap, просто борюсь с ним.

В настоящее время я ожидаю создания заданий Quartz до тех пор, пока пользователь не попросит либо запланировать задание, либо запустить его.Как вы думаете, мне следует создавать задание и инициировать его создание в веб-приложении, а затем извлекать эту информацию из объекта задания для планирования в Quartz?

Ответы [ 2 ]

12 голосов
/ 21 октября 2014

Вам нужен класс 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();
        }
    }
}
4 голосов
/ 21 июля 2011

По второму абзацу: Если я вас правильно понимаю, у вас есть набор заданий, из которых пользователь может выбирать и ставить в определенном порядке исполнения. Я хотел бы подойти к этому, создав экземпляр задания каждого типа задания, выбранного пользователем. Чтобы сохранить порядок заданий, вы можете сохранить имя группы и задание для следующего задания в JobDataMap предыдущего задания. Тогда вы можете иметь общий JobListener, который зарегистрирован для всех заданий. Слушатель получит уведомление, когда задание будет выполнено, и ему будет передан пакет заданий в качестве аргумента. JobListener может перечислять JobDataMap задания, которое только что было выполнено. Если он находит пару ключ-значение с ключом «nextjobname», JobListener запросит планировщик для этого задания. Ссылка на планировщик также доступна в комплекте работ. Если планировщик возвращает экземпляр JobDetail для данного имени, JobListener выполнит его, получит уведомление о его завершении и т. Д., Пока не получит задание с именем «nextjobname» в JobDataMap.
В качестве альтернативы, если вы не хотите иметь прослушиватели Job, у вас может быть базовый класс 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);
    }
}
...