I want to share a custom solution that I needed to implement for lifecycle management problem in a long running application, window service. This scenario valid for windows desktop applications and services, actually this solution is applicable for any scenario that you use thread pooling.
Let’s first mention about the technologies that this post is about.
Quartz.NET is an open source project aimed at creating a free-for-commercial use Job Scheduler, with ‘enterprise’ features.
You can download binaries or source code of the project from its github page.
StructureMap is a Dependency Injection / Inversion of Control tool for .Net that can be used to improve the architectural qualities of an object oriented system by reducing the mechanical costs of good design techniques.
StructureMap is one of my favorite inversion of control container, another one is Windsor. But this post is all about StructureMap container. You can access to StructureMap documentation from its web page and download source code and binaries from its github page.
StructureMap works perfectly with very less configuration, and it has a very easy to discover API to work with. Quartz.NET is a ported project from original Quartz project from Java world (act like you are surprised!).
I had a problem with default configuration options of StructureMap and Quartz.NET. When I needed to have one instance of an object per quartz job. I just made a configuration in StructureMap registry and set that objects lifecycle as HybridHttpOrThreadLocalScoped.
HybridHttpOrThreadLocalScoped is one of the lifecycle scopes that you can use in StructureMap, and this scope creates only one instance of an object per HttpContext or Thread. If it is a web application it uses HttpContext, so you can have only one instance of that object per request comes in your application, or if you are running in a windows service or forms application it creates only one instance of that object per thread.
This seems perfectly good at first but remember it creates one instance per thread. When you are using thread pool you will reuse your threads.
Provides a pool of threads that can be used to execute tasks, post work items, process asynchronous I/O, wait on behalf of other threads, and process timers.
And, Quartz runs jobs, runs each job in a thread, this part sounds good too, but Quartz uses a simple threadpool implementation, you can limit and set maximum number of threads for jobs and Quartz creates number of threads that you defined in your Quartz config and reuses threads.
quartz.threadPool.threadCount – There are 2 threads in the thread pool, which means that a maximum of 2 jobs can be run simultaneously.
Say you set your thread count (quartz.threadPool.threadCount) to 2, when Quartz get initialized it creates 2 threads and reuses these threads for each job run, that means when you run your job for the first time it will get a shinny new thread, second run “probably” based on number of jobs you have scheduled, it will get a shinny new thread too, but third run of that job “probably” will reuse the first thread. This is how it is supposed to work, no problem in Quartz configuration. But remember that we have configured StructreMap as HybridHttpOrThreadLocalScoped, for this example StructureMap (any IoC) will fall the second option and use ThreadLocalScoped. Because of this, StructureMap internal cache will have some objects already created for reuse.
This is not a problem in most scenarios, even it bring some performance benefits with it if you do not have any state in your objects. Say you are creating a data access object which does not need to have manage state between each usage, it is not a problem, actually you don’t event need to manage that lifecycle as thread scoped for that kind of objects.
But another example, actually this was my scenario, if you are managing lifecycle object like UnitOfWork, you will need to have a new instance of this object for each job/thread.
Unit Of Work Pattern definition from Martin Fowler, ThoughtWorks Chief Scientist
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
A note for alternative solution thinkers for having a new UnitOfWork instance for each job run.
You can try to reset to state of an UnitOfWork for each job run at the beginning of each job run but this is not a good way to manage lifecycle of an object. If you go this kind of solution you have to write some reset/initialize state code for each object that you are trying to have a shinny new instance of when you start your job. Which is not a clean way of coding. I prefer to focus on cleanest solution for my scenario which is having a new UnitOfWork for each job run. And this is not a solution just for UnitOfWork, it is about having a object lifecycle per Quartz job run.
Create a new Windows Forms application. Instead of Windows service, I prefer to use a Windows Forms application to spike this solution out, so I can have a better and easier debugging experience.
This is how my packages.config file looks like after adding references.
Update your Program.cs file like shown in below snippet to use StructureMap IoC to active your main form.
Add classes for setting up your StructureMap IoC
Add config app.config and quartzjobs.config (we define this file name in app.config) files for setting Quartz up.
Update MainForm class as shown below. (I renamed Form1 to MainForm.)
Add StructureMapSchedularJobFactory class as show below to be able to use StructureMap IoC to active your Quartz jobs in IoC context so your IoC can manage its all dependecies.
Add this example Quartz Job.
Add UnitOfWork and MyService classes as show below. This is the actual service class that we run for each job. This is not a UnitOfWork pattern implementation off course, it is just a class which has a counter property. We trace this counter value everytime we run our job and we will read this counter value to trace whether we have a shinny new instace of UnitOfWork or we are using an dirty object. (see following MyService implementation for how we do this.)
Let’s run the application and see get a screenshot to see the output.
We have an incrementing numbers in the trace log. That means StructureMap does not pass a new instance of IUnitOfWork implementation every time MyService class initialized.
If you need to get some highlight how this setup works. We created a class custom SchedularJobFactory for Quartz to active job instances in IoC context. This class uses container to active specified job type. And we have registered that job factory implementation in StructureMap registry class.
This is how we configured custom IoC enabled QuartzScheduler. And when we are activating MainForm in Program.cs by using StructureMap, it resolves its dependencies and passes an instance of IoC enabled IScheduler instance.
And when StructureMap actives MyServiceJob, it resolves it’s dependencies and tries to create an instance of IMyService, and IMyService implementation MyService class has a dependency to IUnitOfWork. At this point StructureMap tries to active an instance of IUnitOfWork implementation, UnitOfWork class, and finds a specific lifecycle definition for IUnitOfWork, returns a new instance for each thread, remember we defined as HybridHttpOrThreadLocalScoped, a new instance per thread.
Because of thread pooling implementation in Quartz we reuse threads, and we reuse IUnitOfWork instances.
I think we have demonstrated the problem very clearly with this small spike project.
Solution should create a new object cache in StructureMap per job run! Not per thread!
We have to talk to StructureMap for this and let it be aware of each job run. StructureMap provides extensibility points for custom lifecycle management. If we think simple about this lifecycle management, it is all about having a cache in specified scope!
Let’s see custom lifecycle implementation details in StructureMap, we have to implement an interface, ILifecycle.
We create a HybridHttpQuartzLifecycle class which inherits from HttpLifecycleBase generic type, first generic type we pass this base type is HttpContextLifecycle which still supports HttpContext for web application, we do not use this context for windows apps, for this example we do not need this at all. But second type that we defined in base type is QuartzLifecycle which is our own implementation of Quartz focused context StructureMap lifecycle.
QuartzLifeCycle FindCache methods refers to a “static” property from BaseJob class that we are about to create in our solution.
We have created a base job type for each Quartz job that we are about to define. Very important part in this class definition is ThreadStatic attribute on objectCache “static” variable. ThreadStatic attribute in .NET makes a static variable, static per thread in .NET, you can still access that variable how you access to any static variable but value in that variable will be static per thread.
Indicates that the value of a static field is unique for each thread.
If you ignore that we are calling RegisterANewCache method in Execute method, it is the same thing with using ThreadLocalScoped in StructureMap. But here we have a custom cache variable defined as thread static and we can reset this cache whenever we needed. Really, when we need to reset this thread static cache for StructureMap. Yes! That is right! We have to reset this cache for each job run, it will still be thread static, but we will reset this cache when Quartz runs a job. So, because of that we are calling RegisterANewCache in Execute method (which comes from IJob and gets invoked by Quartz). And we have added an abstract method called ExecuteJob, this gets invoked by Execute after RegisterANewCache method invocation.
RegisterANewCache creates a new instance of MainObjectCache, this is a StructureMap type and StructureMap uses this cache object to store instances per that lifecycle, QuartzLifecycle.
We have to inherit from BaseJob in each Quartz job implementation and override ExecuteJob.
Let’s update our Job implementation and WindowsServiceRegistry as shown below.
We have to update WindowsServiceRegistry class to tell StructureMap to use new custom lifecycle type that we have created.
Let’s run the application and see the screenshot.
As you can see counter values traced as 0, that shows us now we have a new instance of IUnitOfWork implementation, UnitOfWork, per Quartz job run.
One important implementation change in new MyServiceJob is we can not get instance IMyService type in constructor, because when we try to get and instance of IMyService type StructureMap will try to resolve IUnitOfWork type as a dependency of MyService. And StructureMap will use custom lifecycle that we have configured and will get an NullReferenceException in QuartzLifecycle.FindCache method because objectCache variable will not be initialized for that thread yet.
For not to end up with this error we are getting an implementation instance of IMyService in ExecuteJob method by using StructureMap ObjectFactory.
I hope this solution can guide someone who came across same thread pooling related lifecycle management problem in StructureMap and Quartz, or when you are trying to configure any other similar tools. Feedback about solution will be appreciated.