2
votes

I'm new to Quartz.net and just getting a feel for it at the moment. I'm setting up a Quartz.net job to run from my Windows Service.

My Windows service has two modes of initiating a) if the project is run as a windows service, it will run it as a normal service. b) if the project is being run in debug mode from within Visual Studio, it will run an in interactive mode (this is so I can output debug information to the console vs a logger depending on context). It does this as follows in Main() (just an excerpt):

if (Environment.UserInteractive && System.Diagnostics.Debugger.IsAttached) {
    System.Reflection.MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    onStartMethod.Invoke(myService, new object[] { new string[] { } });
    Console.WriteLine("Service started.");
    Console.WriteLine("Press a key to stop service and finish process...");
    Console.ReadKey();
    System.Reflection.MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    onStopMethod.Invoke(myService, null);
    Console.WriteLine("Service stopped.");
} else {
    ServiceBase.Run(myService);
}

Now within MyService I have the following working, and this job seems ro run correctly as expected:

protected override void OnStart(string[] args)
{
    _schedulerFactory = new StdSchedulerFactory();
    IScheduler scheduler = _schedulerFactory.GetScheduler();
    scheduler.Start();

    IJobDetail syncJob = JobBuilder.Create<MySyncJob>()
            .WithIdentity("syncJob")
            .Build();

    ITrigger trigger = TriggerBuilder.Create()
        .StartAt(new DateTimeOffset(DateTime.UtcNow.AddSeconds(5)))
        .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())
        .Build();

    scheduler.ScheduleJob(syncJob, trigger);

}

However when I run my project in debug mode from my Visual Studio, when I stop the service, the console says "Service stopped", but the Quartz.net syncJob seems to keep running (the console output continues) Why would this be?

1
What does your OnStop look like? - Dean Ward
Nothing substantial in OnStop. Just "GC.RemoveMemoryPressure(GC.GetTotalMemory(true)); GC.Collect();". Do I need to explicitly stop those jobs in OnStop? - Manachi
Why are you reinventing the wheel? Quartz.Server.exe See : geekswithblogs.net/TarunArora/archive/2012/11/16/… There is already a code-base for a quartz.net windows service. - granadaCoder

1 Answers

6
votes

You need to update your OnStop method to shutdown the scheduler when your service is stopped.

private ISchedulerFactory _schedulerFactory;
private IScheduler _scheduler;

protected override void OnStart(string[] args)
{
    _schedulerFactory = new StdSchedulerFactory();
    _scheduler = _schedulerFactory.GetScheduler();
    _scheduler.Start();

    IJobDetail syncJob = JobBuilder.Create<MySyncJob>()
        .WithIdentity("syncJob")
        .Build();

    ITrigger trigger = TriggerBuilder.Create()
        .StartAt(new DateTimeOffset(DateTime.UtcNow.AddSeconds(5)))
        .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())
        .Build();

    scheduler.ScheduleJob(syncJob, trigger);

}

protected override void OnStop()
{
    // true parameter indicates whether to wait for running jobs
    // to complete before completely tearing down the scheduler
    // change to false to force running jobs to abort.
    _scheduler.Shutdown(true);
}

As a sidenote, you might want to consider using Topshelf which helps dealing with the teardown and setup of windows services without all the boiler plate bits you show at the start of your question.