Executing multiple Quartz.NET jobs with Topshelf

Citrus picture Citrus · Aug 14, 2014 · Viewed 8k times · Source

I am attempting to run multiple jobs with Quartz.NET and Topshelf using C#.

HostFactory.Run(c =>
{
    c.ScheduleQuartzJobAsService(q =>
        q.WithJob(() => JobBuilder.Create<TypeA>().Build())
        .AddTrigger(() => TriggerBuilder.Create().WithSimpleSchedule(builder => builder.WithIntervalInSeconds(ConfigurationSettings.AppFrequencyInSeconds).RepeatForever()).Build())
        ).StartAutomatically().
        ScheduleQuartzJobAsService(r => 
        r.WithJob(() => JobBuilder.Create<TypeB>().Build())
        .AddTrigger(() => TriggerBuilder.Create().WithSimpleSchedule(builder => builder.
            WithIntervalInSeconds(ConfigurationSettings.AppFrequencyInSeconds).RepeatForever()).Build())
            ).StartAutomatically();
    c.StartAutomatically();
    c.SetServiceName("ServiceName");
});

Using the above code, only the execute method in TypeB gets executed. I have also tried:

HostFactory.Run(c =>
{
    c.ScheduleQuartzJobAsService(q =>
        q.WithJob(() => JobBuilder.Create<TypeA>().Build())
        .AddTrigger(() => TriggerBuilder.Create().WithSimpleSchedule(builder => builder.
            WithIntervalInSeconds(ConfigurationSettings.AppFrequencyInSeconds).RepeatForever()).Build())
        ).StartAutomatically();
    c.StartAutomatically();
    c.SetServiceName("Service1");

    c.ScheduleQuartzJobAsService(r =>
        r.WithJob(() => JobBuilder.Create<TypeB>().Build())
        .AddTrigger(() => TriggerBuilder.Create().WithSimpleSchedule(builder => builder.
            WithIntervalInSeconds(ConfigurationSettings.AppFrequencyInSeconds).RepeatForever()).Build())
        ).StartAutomatically();
    c.StartAutomatically();
    c.SetServiceName("Service2");
});

With this code, only the execute method in TypeB is called. Both my classes TypeA and TypeB have 'Execute' methods which are the entry points for each class (which do get called if they are part of a job on their own). It seems that whichever service code is second is the one that is always called - if I swap the order of these two ScheduleQuartzJobAsService calls it is always the class in the second call that is executed.

How can I write my HostFactory.Run method so both jobs are executed concurrently?

Answer

Citrus picture Citrus · Aug 15, 2014
HostFactory.Run(c =>
                {
                    c.Service<ContainerService>(s =>
                    {
                        s.ConstructUsing(name => new ContainerService());
                        s.WhenStarted((service, control) => service.Start());
                        s.WhenStopped((service, control) => service.Stop());

                        s.ScheduleQuartzJob<ContainerService>(q =>
                            q.WithJob(() =>
                                JobBuilder.Create<TypeA>().Build())
                            .AddTrigger(() =>
                                TriggerBuilder.Create()
                                    .WithSimpleSchedule(builder => builder
                                        .WithIntervalInSeconds(20)
                                        .RepeatForever())
                                    .Build())
                            );

                        s.ScheduleQuartzJob<ContainerService>(q =>
                            q.WithJob(() =>
                                JobBuilder.Create<TypeB>().Build())
                            .AddTrigger(() =>
                                TriggerBuilder.Create()
                                    .WithSimpleSchedule(builder => builder
                                        .WithIntervalInSeconds(60)
                                        .RepeatForever())
                                    .Build())
                            );
                    });

                });

...

public class ContainerService
{
    public bool Start()
    {
        return true;
    }

    public bool Stop()
    {
        return true;
    }
}

My problem was I was mixing up the concepts of the service and job classes. As soon as I introduced my ContainerService with Start() and Stop() bool methods that returned true, and I called ScheduleQuartzJob rather than ScheduleQuartzJobAsService the above code worked for me as my TypeA and TypeB already implemented IJob.