Quartz.NET – remote scheduler without job assembly reference on the client side

I have seen few tutorials showing how to schedule Quartz.NET jobs on the remote process using scheduler proxy and all of them suffered th e same inconvenience – they assumed that jobs assembly is added as a reference to the both client and a server projects. In my opinion this is a serious architecture smell because jobs are most certainly part of your business logic (in the scenarios I can think of) and it can cause problems with deployment (imagine one server running Quartz.NET scheduler and few or dozens of clients) and could cause some security issues (disassembling etc.). I really think that jobs should be placed in the business logic, not visible to clients which should be able to schedule them using some kind of contract / interface.

Here is how to achieve this.

Job contract – referenced by client and server side. Exposes only information required to identify a job and prepare its parameters:

//contract for the job - simple class with constant unique job name and some helper method
//used to create parameters for the job instance
public class SomeJobContract
{
	public const string JobName = "SomeApi.SomeJobUniqueName";

	public const string SomeParameterName = "BusinessObjectId";

	public static IDictionary<string, object> BuildJobDetails(int businessObjectId)
	{
		return new Dictionary<string, object>()
		{
			{ SomeParameterName, businessObjectId }
		};
	}
}

Job implementation – its type can not be resolved on the client side because there is no reference to the implementation assembly:

//implementation of the job which contract is exposed
public class SomeJob : IJob
{
	public void Execute(IJobExecutionContext context)
	{
		//use data passed with trigger - context.Trigger instead of context.JobDetails.JobDataMap
		var businessObjectId = (int?)context.Trigger.JobDataMap[SomeApi.SomeJobContract.SomeParameterName];
		
		//... regular job code
	}
}

Server code used to register a specific job (using its type) with a unique identifier exposed in contract and hence known to the client:

//create job details - use unique job identifier
var preProcessingJob = JobBuilder.Create<SomeJob>()
                .StoreDurably(true)
                .RequestRecovery(true)
                .WithIdentity(SomeApi.SomeJobContract.JobName)
                .Build();

//add a durable job to scheduler without using a trigger
scheduler.AddJob(preProcessingJob, true, true);

Client side code used to schedule the job with appropriate parameters – uses only information exposed by the contract assembly:

//create a trigger for the job with specified identifier (we use contract, we have no reference to job implementation on the client side)
var trigger = TriggerBuilder
                .Create()
                .ForJob(SomeApi.SomeJobContract.JobName)
                .UsingJobData(new JobDataMap(SomeApi.SomeJobContract.BuildJobDetails(myBusinessObjectId)))
                .WithSimpleSchedule().StartNow()
                .Build();

schedulerProxy.ScheduleJob(trigger);
Advertisements

One Response to Quartz.NET – remote scheduler without job assembly reference on the client side

  1. Anil Jain says:

    Hi,

    Tried the above code but it isnt working:
    1) My remote job is a console app.
    2) Job contract as shown in this article.
    3) ASP.NET Web API as the client.

    When I run this it throws exception.

    The job (DEFAULT.TestJob) referenced by the trigger does not exist.”

    Thanks

    Anil

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: