310 likes | 2.7k Views
Asynchronous Job Processing Using Quartz.Net. Jay Vilalta jay.vilalta@gmail.com. What Is Quartz.Net. Scheduler (think task scheduler) Queue for asynchronous jobs C# port of Quartz (java) Apache license. Why Use Quartz.Net. Scale out Redundancy Smart handling of failures
E N D
Asynchronous Job ProcessingUsing Quartz.Net Jay Vilalta jay.vilalta@gmail.com
What Is Quartz.Net • Scheduler (think task scheduler) • Queue for asynchronous jobs • C# port of Quartz (java) • Apache license
Why Use Quartz.Net • Scale out • Redundancy • Smart handling of failures • Job chaining (poor man’s workflow) • Custom scheduling
How Can I Run It • Embedded in your application • As a stand alone windows service
The Basics • Scheduler • Jobs • Triggers
Scheduler • Runs jobs • Manages the scheduling
Jobs • Do the work • Some built-in • Mostly roll you own • Implement IJob
Built-in Jobs • FileScanJob: monitors last modified date • NativeJob: runs executables or batch files • NoOpJob: does nothing • SendMailJob: sends emails
Jobs - Example public class MyJob : IJob { public void Execute(JobExecutionContext context) { try { int count= context.MergedJobDataMap.GetIntegerFromString(“count"); for (int i = 0; i < count; i++){ //do something useful } } catch (ApplicationException ex) { throw new JobExecutionException("Something happened", ex, false); } } }
Triggers • Tell the scheduler when jobs should run • Some built-in • Simple Trigger • Cron Trigger • NthIncludedDayTrigger • Custom Triggers
Simple Trigger • Start Time • Repeat Count • Repeat Interval
Cron Trigger • Similar to UNIX cron • Start Time • Cron Expression • “0 15 10 ? * *” • “0 0,15,30,45 * ? * *”
Custom Triggers • No example this time • Implementing a trigger is not trivial • Must implement 11 methods • Must be able to determine next fire time
Scheduling • Associate a job to a trigger • Multiple triggers can be set • When the trigger fires, the job runs scheduler.ScheduleJob(jobDetail, trigger);
Advanced Features • Listeners • Special Jobs • Remote management • Clustering • Plug-ins • Unit testing
Listeners • Job Listeners • Trigger Listeners • Scheduler Listeners • Job and trigger listeners can be global
Job Listener Example public class JobHistoryListener : IJobListener { public void JobExecutionVetoed(…) public void JobToBeExecuted(…) public void JobWasExecuted(…) }
Trigger Listener Example public class MyTriggerListener:ITriggerListener { public string Name public void TriggerComplete(…) public void TriggerFired(…) public void TriggerMisfired(…) public bool VetoJobExecution(…) }
Special Jobs • Stateful Jobs • Interruptible Jobs
Stateful Jobs • Only one can run at a time • Allow you to save/restore state • You must manage state yourself • Implement IStatefulJob
Interruptible Jobs • Mechanism to interrupt long running jobs • You must implement yourself • Implement IInterruptableJob
Remote Management • Scheduler can be managed remotely • Exposed via Remoting • Most scheduler functions available
JobFactory • Instantiates jobs • Default factory creates a new instance • Create your own if you use DI or IoC container
Job Stores • RAMJobStore • AdoJobStore • MySql • Oracle • Postgres • SQL Lite • SQL Server
Clustering • Load balancing • Job Failover • Caveat: clocks synchronized within a second
Plug-ins • JobInitializationPlugin • LoggingJobHistoryPlugin • LoggingTriggerHisotryPlugin • ShutdownHookPlugin
Plug-ins Stub public class SamplePlugin : ISchedulerPlugin { public void Initialize(string name, IScheduler sched) public void Shutdown() public void Start() }
Unit Testing • You can / should unit test your quartz classes • Use a mocking framework • Mock the Scheduler (IScheduler) • Mock a calendar (ICalendar) • Use mocks to create your context
Sample Unit Test [Test] public void ExecuteTests() { JobDetail detail = new JobDetail(); IScheduler scheduler = new Mock<IScheduler>().Object; ICalendar calendar = new Mock<ICalendar>().Object; IJob job = new NoOpJob(); detail.Name = "Test"; detail.JobDataMap.Add("SOMETHING", "ELSE"); TriggerFiredBundle bundle = new TriggerFiredBundle(detail, new SimpleTrigger(), calendar, false, null, null, null, null); JobExecutionContext context = new JobExecutionContext(scheduler, bundle, job); JobHistoryListener listener = new JobHistoryListener(); listener.JobToBeExecuted(context); listener.JobWasExecuted(context, null); //methods return void so need to get creative to determine if execution was successful } }
Resources Project Home: http://quartznet.sourceforge.net/ Mailing List: http://groups.google.com/group/quartznet Getting Started: http://jvilalta.blogspot.com