Topshelf needs to use Autofac's Quartz job factory

3.3k views Asked by At

I'm trying to use TopShelf together with Quartz.net and Autofac. The code I have below works just fine. However, this line:

cfg.UsingQuartzJobFactory(() => container.Resolve<IJobFactory>());

seems like the wrong way of doing things. Is there a better way of telling Topshelf to use the custom autofac jobfactory? What lifetime scope will the jobfactory have? I'm concerned this line of code is going to cause me some headaches sometime in the future. How do I release the jobfactory when it's no longer needed? Is this line okay as-is?

class Poller : IJob
{
    private readonly ILogger _log;

    public Poller(ILogger log)
    {
        _log = log;
        _log.Info("Instantiating...");
    }

    public void Execute(IJobExecutionContext context)
    {
        _log.Info("Executing...");
    }
}

class Program
{
    static Autofac.IContainer BuildContainer()
    {
        var builder = new ContainerBuilder();

        builder.RegisterModule<NLogModule>();
        builder.RegisterModule<QuartzAutofacFactoryModule>();
        builder.RegisterModule(new QuartzAutofacJobsModule(typeof(Poller).Assembly));

        var container = builder.Build();
        return container;
    }

    static void Main(string[] args)
    {
        var container = BuildContainer();

        HostFactory.Run(cfg =>
        {
            cfg.UseNLog();
            cfg.UseAutofacContainer(container);
            cfg.SetDescription("DESCRIPTION");
            cfg.SetDisplayName("DISPLAY");
            cfg.SetServiceName("NAME");

            cfg.UsingQuartzJobFactory(() => container.Resolve<IJobFactory>());

            cfg.ScheduleQuartzJobAsService(q =>
            {
                q.WithJob(() => JobBuilder.Create<Poller>().Build());
                q.AddTrigger(() => TriggerBuilder.Create().WithSimpleSchedule(b => b.WithIntervalInSeconds(20).RepeatForever()).Build());
            });

            cfg.StartAutomatically();
            cfg.RunAsLocalSystem();

        });
    }
}

For reference: TopShelf.Quartz.ScheduleHobHostConfiguratorExtensions

Also reference: Autofac.Extras.Quartz.QuartzAutofacFactoryModule

1

There are 1 answers

0
Donald On

I think you should initialize quartz Server with container, this example use unity, but I am sure that work with other containers.

try
        {
            var container = new UnityContainer();
            schedulerFactory = CreateSchedulerFactory();
            quartzscheduler = GetScheduler();
            SyncPost.Initialize.RepositoryConfig(container);
            SyncPost.Initialize.AddToSchedulerContextCustomVars(quartzscheduler, container);
            quartzscheduler.JobFactory = new JobFactoryInjection(container);

        }
        catch (Exception e)
        {
            logger.Error("Server initialization failed:" + e.Message, e);
            throw;
        }

where JobFactoryInjection implement IJobFactory:

 public class JobFactoryInjection : IJobFactory
{

        private readonly UnityContainer container = new UnityContainer(); 

        public JobFactoryInjection(UnityContainer container)
        {

            if (container == null) throw new ArgumentNullException("container", "Container is null");
            this.container = container;
        }



    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) {


            // Return job registrated in container
            bundle.JobDetail.JobDataMap.Put(SyncUtils.ContextKeyCenterCode, scheduler.Context.Get(SyncUtils.ContextKeyCenterCode));
            return (IJob)container.Resolve(bundle.JobDetail.JobType);

    }

    public void ReturnJob(IJob job) {

    }
}

About JobFactory lifetime, don't worry about it. From Quartz documentation: "JobFactory simply activates a new instance of the job class. You may want to create your own implementation of JobFactory to accomplish things such as having your application's IoC or DI container produce/initialize the job instance"