HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Parallel Job Consumer using TPL

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
parallelusingconsumertpljob

Problem

I need to provide a service (either a Windows Service or an Azure Worker Role) which will handle the parallel execution of jobs. These jobs could be anything from importing data to compiling of reports, or to sending out mass notifications, etc.

Database Design:

The whole process of running these jobs is persistent.

  • JobDefinition stores varchar reference to the IJob concrete type class.



  • JobInstance is an instance of JobDefinition which needs to be executed as a job.



  • JobInstanceEvent stores the process of executing an instance (the change of states).



Class Structure:

In order to create new jobs the simple IJob interface needs to be implemented:

public interface IJob
{
    bool Execute();
}


JobHandler is responsible for deserializing the serialized varchar in the database and also saving state changes:

```
public class JobHandler
{
public string State
{
get
{
return jobInstance.State;
}
set
{
using (MyEntities context = new MyEntities())
{
context.JobInstances.Attach(jobInstance);
jobInstance.State = value;

context.SaveChanges();
}

SaveJobEvent(String.Empty);
}
}

private JobInstance jobInstance;

public JobHandler(JobInstance job)
{
jobInstance = job;
}

public IJob CreateJobObject()
{
Type type = Type.GetType(jobInstance.JobDefinition.FullAssemblyType);

XmlSerializer serializer = new XmlSerializer(type);
using (StringReader reader = new StringReader(jobInstance.SerialisedObject))
{
return serializer.Deserialize(reader) as IJob;
}
}

public void SaveJobEvent(string jobEventMessage)
{
using (MyEntities context = new MyEntities())
{
context.JobInstances.Attach(jobInstance);

jobInstance.JobInstanceEvents.Add(
n

Solution

Only some few minor things:

  • In StartPopulatingQueue to me as the reader it's unclear in what unit pollingDelay is in. Two classic solutions:



  • Change it to be a TimeSpan - I usually prefer this since it provides the most flexibility.



  • Add the unit suffix to the parameter name. like Ms for milliseconds or Sec for seconds etc.



  • CreateJobObject can potentially return null if the deserialized object cannot be cast to IJob in which case ExecuteJob will throw a NullReferenceException which is typically not very meaningful. You should throw a more meaningful exception on deserialization (as mentioned in the comment by Roman you could use a direct cast instead of as which would throw an InvalidCastException)



  • It feels wrong to me that the consumer defines the job execution states. The consumer seems largely responsible for managing the job queue and it should stick to that single responsibility. Hence I think Execute should be moved into JobHandler.



  • I'd also consider moving CreateJobObject to JobInstance so JobInstance is responsible to provide the actual object instance. Then JobHandler is just concerned with the state changes of the job.

Context

StackExchange Code Review Q#32073, answer score: 3

Revisions (0)

No revisions yet.