Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quartz.net CancellationToken

In my scheduler, implemented with quartz.net v3, i'm trying to test the behaviour of the cancellation token:

....
IScheduler scheduler = await factory.GetScheduler();
....
var tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
// Start scheduler
await scheduler.Start(ct);
// some sleep 
await Task.Delay(TimeSpan.FromSeconds(60));
// communicate cancellation
tokenSource.Cancel();

I have a test Job that runs infinitely and in the Execute method checks the cancellation token:

public async Task Execute(IJobExecutionContext context)
{
    while (true)
    {
        if (context.CancellationToken.IsCancellationRequested)
        {
            context.CancellationToken.ThrowIfCancellationRequested();
        }
    }
}

I would expect that when tokenSource.Cancel() is fired the job will enter in the if and throws the Exception. But it doesn't work.

like image 373
luke88 Avatar asked Jan 24 '18 17:01

luke88


2 Answers

According to the documentation, you should use Interrupt method to cancel Quartz jobs.

NameValueCollection props = new NameValueCollection
{
    { "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
var scheduler = await factory.GetScheduler();
await scheduler.Start();
IJobDetail job = JobBuilder.Create<HelloJob>()
    .WithIdentity("myJob", "group1")
    .Build();
ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity("myTrigger", "group1")
    .StartNow()
    .WithSimpleSchedule(x => x
        .WithRepeatCount(1)
        .WithIntervalInSeconds(40))
    .Build();
await scheduler.ScheduleJob(job, trigger);
//Configure the cancellation of the schedule job with jobkey
await Task.Delay(TimeSpan.FromSeconds(1));
await scheduler.Interrupt(job.Key);

Scheduled job class;

public class HelloJob : IJob
{
    public async Task Execute(IJobExecutionContext context)
    {
        while (true)
        {
            if (context.CancellationToken.IsCancellationRequested)
            {
                context.CancellationToken.ThrowIfCancellationRequested(); 
                // After interrupt the job, the cancellation request activated
            }
        }
    }
}

Apply scheduler.Interrupt after the job executed and the quartz will terminate the job.

EDIT

According to source code (Line 2151), the Interrupt method applys cancellation tokens of the job execution contexts. So, it could be better to use facility of the library.

like image 123
lucky Avatar answered Oct 19 '22 16:10

lucky


Here is a Unit Test from Github Repo: https://github.com/quartznet/quartznet/blob/master/src/Quartz.Tests.Unit/InterrubtableJobTest.cs

I tried to implement the cancellation the same way, but it didn't work for me either.

@Stormcloak I have to check the cancellation request because I want to do some aborting operations for the job, e.g. write status data to a database.

EDIT:

So, after multiple tests and implementations. I've got it running.

Some Pseudo code here:

    this.scheduler = await StdSchedulerFactory.GetDefaultScheduler();
    this.tokenSource = new CancellationTokenSource();
    this.token = tokenSource.Token;
    // Start scheduler.
    await this.scheduler.Start(token);
    // add some jobs here
    // ...
    // cancel running jobs.
    IReadOnlyCollection<IJobExecutionContext> jobs = await this.scheduler.GetCurrentlyExecutingJobs();
    foreach (IJobExecutionContext context in jobs)
    {
       result = await this.scheduler.Interrupt(context.JobDetail.Key, this.token);
    }
    await this.scheduler.Shutdown(true);

So now you can use the CancellationToken in your Execute method.

like image 27
Zar Avatar answered Oct 19 '22 16:10

Zar