IScheduler.Shutdown(true) does not appear to be waiting for jobs to finish in version 3.1

45 views
Skip to first unread message

Richard Beacroft

unread,
Aug 5, 2020, 10:55:50 AM8/5/20
to Quartz.NET
Hi,

We just tried upgrading Quartz.Net from 2.6.2 to the latest version 3.1.
We tried to adapt our code as shown below and we found that when we stop the windows service, the Shutdown method on the scheduler does not appear to wait for the job to complete.
I'm sure there is something silly we have missed, but we cannot see what. 
Are you able to shed some light.

Example code below...

    public class ExampleQuartzScheduler
   
{
       
private readonly ISchedulerFactory _schedulerFactory;
       
private IScheduler _scheduler = null;


       
public ExampleQuartzScheduler()
       
{
            _schedulerFactory
= new Quartz.Impl.StdSchedulerFactory();
       
}


       
public async void Start()
       
{
           
StopServiceSingleton.Stop = false;


           
if (_scheduler == null)
                _scheduler
= await _schedulerFactory.GetScheduler();


           
SetupExampleJob();


            await _scheduler
.Start();
       
}


       
private async void SetupExampleJob()
       
{
           
var jobKeyName = "Example-Job";
           
var triggerKeyName = $"ExampleJob-Trigger";
           
var triggerKey = new TriggerKey(triggerKeyName, jobKeyName);


           
// to avoid adding a job that is already added, un-schedule it first.
            await _scheduler
.UnscheduleJob(triggerKey);


           
IJobDetail job = JobBuilder.Create<MailSenderQuartzJobHandler>().WithIdentity(jobKeyName, jobKeyName).Build();


           
var trigger = TriggerBuilder.Create()
                                       
.WithIdentity(triggerKey)
                                       
.StartAt(DateTime.Now)
                                       
.WithSimpleSchedule(s => s.WithIntervalInSeconds(2).RepeatForever())
                                       
.Build();


            await _scheduler
.ScheduleJob(job, trigger);
       
}


       
public async void Stop()
       
{
            if (_scheduler == null)
                return;

           
StopServiceSingleton.Stop = true;


           
// WHY DOES THIS NOT WAIT FOR ExampleJob TO FINISH?
            await _scheduler
.Shutdown(waitForJobsToComplete: true);
       
}
   
}


   
public partial class ExampleWindowsService : System.ServiceProcess.ServiceBase
   
{
       
private readonly ExampleQuartzScheduler _processor;


       
public ExampleWindowsService()
       
{
            _processor
= new ExampleQuartzScheduler();
       
}


       
protected override void OnContinue()
       
{
           
if (CanPauseAndContinue)
                _processor
.Start();
       
}


       
protected override void OnPause()
       
{
           
if (CanPauseAndContinue)
                _processor
.Stop();
       
}


       
protected override void OnShutdown()
       
{
           
if (CanShutdown)
                _processor
.Stop();
       
}


       
protected override void OnStart(string[] args)
       
{
            _processor
.Start();
       
}


       
protected override void OnStop()
       
{
           
if (CanStop)
                _processor
.Stop();
       
}
   
}


   
public class ExampleJob : IJob
   
{
       
public async Task Execute(IJobExecutionContext context)
       
{
           
var tasks = new List<Task>();


           
// example only
            tasks
.Add(Task.Factory.StartNew(() => { Thread.Sleep(20000); }, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness));
           
            await
Task.WhenAll(tasks.ToArray());
       
}
   
}



Marko Lahma

unread,
Aug 5, 2020, 12:19:34 PM8/5/20
to Quartz. NET

In these cases I'd strongly recommend enabling logging. It probably will give you more insights.

But there are things that seem a bit off:

* "async void" method signatures, never do that. Use "async Task" methods and await them
* OnStop doesn't await, so you lose the control, at least do _processor.Stop().GetAwaiter().GetResults();, same for start
* in job maybe simulate just by doing "return Task.Delay(Timespan.FromSeconds(20));", Thread.Sleep is blocking and takes the fun away

When you don't properly await, execution continues and process ends.

-Marko

PS. There's new discussion feature on GitHub, it makes code sharing / highlighting and notifications hopefully easier: https://github.com/quartznet/quartznet/discussions


--
You received this message because you are subscribed to the Google Groups "Quartz.NET" group.
To unsubscribe from this group and stop receiving emails from it, send an email to quartznet+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/quartznet/b4cdb97e-b12e-4a9a-999a-60893260e528o%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages