15

Does anyone have any experience integrating autofac and Quartz.Net? If so, where is it best to control lifetime management -- the IJobFactory, within the Execute of the IJob, or through event listeners?


Right now, I'm using a custom autofac IJobFactory to create the IJob instances, but I don't have an easy way to plug in to a ILifetimeScope in the IJobFactory to ensure any expensive resources that are injected in the IJob are cleaned up. The job factory just creates an instance of a job and returns it. Here are my current ideas (hopefully there are better ones...)

  • It looks like most AutoFac integrations somehow wrap a ILifetimeScope around the unit of work they create. The obvious brute force way seems to be to pass an ILifetimeScope into the IJob and have the Execute method create a child ILifetimeScope and instantiate any dependencies there. This seems a little too close to a service locator pattern, which in turn seems to go against the spirit of autofac, but it might be the most obvious way to ensure proper handling of a scope.

  • I could plug into some of the Quartz events to handle the different phases of the Job execution stack, and handle lifetime management there. That would probably be a lot more work, but possibly worth it if it gets cleaner separation of concerns.

  • Ensure that an IJob is a simple wrapper around an IServiceComponent type, which would do all the work, and request it as Owned<T>, or Func<Owned<T>>. I like how this seems to vibe more with autofac, but I don't like that its not strictly enforceable for all implementors of IJob.

David Faivre
  • 2,302
  • 3
  • 23
  • 25

2 Answers2

11

Without knowing too much about Quartz.Net and IJobs, I'll venture a suggestion still.

Consider the following Job wrapper:

public class JobWrapper<T>: IJob where T:IJob
{
    private Func<Owned<T>> _jobFactory;

    public JobWrapper(Func<Owned<T>> jobFactory)
    {
        _jobFactory = jobFactory;
    }


    void IJob.Execute()
    {
        using (var ownedJob = _jobFactory())
        {
            var theJob = ownedJob.Value;
            theJob.Execute();
        }
    }
}

Given the following registrations:

builder.RegisterGeneric(typeof(JobWrapper<>));
builder.RegisterType<SomeJob>();

A job factory could now resolve this wrapper:

var job = _container.Resolve<JobWrapper<SomeJob>>();

Note: a lifetime scope will be created as part of the ownedJob instance, which in this case is of type Owned<SomeJob>. Any dependencies required by SomeJob that is InstancePerLifetimeScope or InstancePerDependency will be created and destroyed along with the Owned instance.

Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131
  • thanks for taking the time to respond. I like the idea in that it is a more explicit version of my third brainstorm in the original question. What still bugs me is that I have no control over a lifetime scope. Basically, I'd like to run each IJob in its own `LifetimeScope`, almost as the equivalent of a WCF service call. The Quartz `IJobFactory` unfortunately is pretty much fire and forget from what I've been able to tell, so it may be that if I really want explicit scope boundaries, I'd have to dig into the Quartz listener system. – David Faivre Feb 07 '11 at 20:08
  • @dfaivre - I've corrected a bug in my code, I forgot the `ownedJob.Value` part. Perhaps my intentions are clearer now. – Peter Lillevold Feb 07 '11 at 22:20
  • 3
    I did not know that Owned created a scope; very useful. I think this is probably the most straight forward approach then without a deep dive into the Quartz stack. I'll probably augment my `IJobFactory` to throw if job is not of type `JobWrapper<>` (just so I sleep a little better at night...). Thanks again for the great insight. – David Faivre Feb 07 '11 at 22:57
  • 1
    So, a couple years later, I realized I misunderstood this answer, and that is an even better answer than I first though. I was creating my jobs explicitly as a subclass of `JobWrapper<>`, which still tightly coupled me to Autofac, when really, I should have just been letting the `AutofacJobFactory` dynamically create the wrapper for me, allowing the underlying IJob to just declare its dependencies. Some days... – David Faivre Jul 17 '13 at 14:03
  • @dfaivre - oh! Glad you found out! :-) – Peter Lillevold Jul 17 '13 at 14:57
7

Take a look at https://github.com/alphacloud/Autofac.Extras.Quartz. It also available as NuGet package https://www.nuget.org/packages/Autofac.Extras.Quartz/

I know it a bit late:)

shatl
  • 911
  • 16
  • 21