Quartz.NET–planowanie zadań

Czasami potrzeba nam prostego narzędzia, które będzie wykonywało jakieś zadania w określonych ramach czasowych. Można użyć prostego Timera z .NET Framework, ale ma on dość ograniczone możliwości. Na przykład, stan zadań nie może być zapisany w bazie danych. Dla bardzo zaawansowanych rozwiązań, zwykle mamy inną architekturę, na przykład opartą na kolejkach. W takich sytuacjach, zwykle poszczególne technologie posiadają swoje mechanizmy, tak jak nServiceBus o który już wiele razy pisałem.

Dzisiaj jednak chciałbym przedstawić Quartz.NET – lekka biblioteka, która nada się do do prostych przypadków, dla których jednak czysty, standardowy timer ma zbyt małe możliwości.

Standardowo instalujemy pakiet z NuGet:

image

API jest bardzo proste. Standardowy szablon  wygląda następująco:

try { IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler(); scheduler.Start(); Thread.Sleep(1000000); scheduler.Shutdown(); } catch (SchedulerException ex) { Console.WriteLine(ex); }

Koniecznie należy wywołać Shutdown na koniec.  W przeciwnym wypadku, wciąż w aplikacji istniałyby wątki przeznaczone do wykonywania zadań.  Same zadanie definiuje się poprzez implementację interfejsu IJob:

class PrintTextJob : IJob { public void Execute(IJobExecutionContext context) { Console.WriteLine("Test: {0}",DateTime.Now); } }

Następnie należy ją dodać do scheduler’a:

IJobDetail job = JobBuilder.Create<PrintTextJob>().Build(); ITrigger trigger = TriggerBuilder.Create(). StartNow(). WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever()).Build(); scheduler.ScheduleJob(job, trigger);

Definicja Triggera jest tutaj chyba najważniejsza. Szczegóły znajdują się oczywiście w dokumentacji, ale istnieje wiele sposób zdefiniowania kiedy zadanie ma wykonać się. Do dyspozycji mamy nawet cron expression:

TriggerBuilder.Create().WithCronSchedule("0 42 10 * * ?")

Można również zdefiniować zachowanie scheduler’a za pomocą pliku konfiguracyjnego:

quartz.scheduler.instanceName = MyScheduler quartz.threadPool.threadCount = 3 quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz

Jak widać, można określić liczbę wątków oraz typ bazy. Domyślnie jest to in-memory, ale nic nie stoi na przeszkodzie, aby zapisać wyzwalacze czy zadania w innym typie bazy.

Quartz wspiera wykonywanie logów i możemy je zdefiniować za pomocą:

Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter {Level = Common.Logging.LogLevel.Info};

Możemy również śledzić wszelkie wykonywane operacje np. poprzez implementacje interfejsu ISchedulerListener:

public interface ISchedulerListener { void JobScheduled(Trigger trigger); void JobUnscheduled(string triggerName, string triggerGroup); void TriggerFinalized(Trigger trigger); void TriggersPaused(string triggerName, string triggerGroup); void TriggersResumed(string triggerName, string triggerGroup); void JobsPaused(string jobName, string jobGroup); void JobsResumed(string jobName, string jobGroup); void SchedulerError(string msg, SchedulerException cause); void SchedulerShutdown(); }

Następnie zaimplementowany listener należy dodać, a po wszystkim oczywiście usunąć:

scheduler.ListenerManager.AddSchedulerListener(mySchedListener); scheduler.ListenerManager.RemoveSchedulerListener(mySchedListener);

Analogicznie sprawa wygląda z ITriggerListener oraz IJobListener:

public interface ITriggerListener { string Name { get; } void TriggerFired(ITrigger trigger, IJobExecutionContext context); bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context); void TriggerMisfired(ITrigger trigger); void TriggerComplete(ITrigger trigger, IJobExecutionContext context, int triggerInstructionCode); } public interface IJobListener { string Name { get; } void JobToBeExecuted(IJobExecutionContext context); void JobExecutionVetoed(IJobExecutionContext context); void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException); }

Następnie wystarczy wywołać scheduler.ListenerManager.AddJobListener.

4 thoughts on “Quartz.NET–planowanie zadań”

  1. Czy scheduler z powyższego przykładu jest FIFO? Tzn czy kolejne zadanie wykona się dopiero po zakończeniu pierwszego?

Leave a Reply

Your email address will not be published.