C# – In Quartz.net, run one instance of a job at a time

cquartz.net

I have referred the following question but didn't help me to solve the issue.

In Quartz.NET is there a way to set a property that will only allow one instance of a Job to run?

https://github.com/quartznet/quartznet/issues/469

For CronTrigger, Used the following in the scheduler cs.WithMisfireHandlingInstructionDoNothing().

Applied the following attribute in the HelloJob

DisallowConcurrentExecution.

What happened with the code?
In the Execute method, I have set the breaking point. Based on my code the execute method will execute in 10 seconds each.

After hitting the first breaking point, I have waited for another 31 seconds. Then I have removed the breaking point and executed the code, based on my expectation, that should be execute only one time for another attempt.

But the execute method executed 3 times (3*10 seconds) within another
10 seconds.

How to solve this?

Scheduler code.

ISchedulerFactory schedFact = new StdSchedulerFactory();
IScheduler sched = schedFact.GetScheduler();
sched.Start();

// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>()
    .WithIdentity("myJob", "group1")
    .Build();

// Trigger the job to run now, and then every 40 seconds
ITrigger trigger = trigger = TriggerBuilder.Create()
    .WithIdentity("trigger3", "group1")
    .WithCronSchedule("0/10 * * * * ?",cs=>cs.WithMisfireHandlingInstructionDoNothing())
    .ForJob("myJob", "group1")
    .Build();

TriggerKey key = new TriggerKey("trigger3", "group1");
sched.ScheduleJob(job, trigger);

Job execution code.

[DisallowConcurrentExecution]
public class HelloJob : IJob
{        
     public static int count = 1;
    public void Execute(IJobExecutionContext context)
    {
         Console.WriteLine(count+" HelloJob strted On." + DateTime.Now.ToString());
        if (count == 1)
            Thread.Sleep(TimeSpan.FromSeconds(30));

        Interlocked.Increment(ref count);
    }
}

enter image description here

====================================================================

Solution

No need to go for interlocked or manual management.

Quartz is already designed like only finishes the first schedule, the next one starts.

So we no need to worry about that it will run concurrently.

For example (The people like me :-p), the scheduler scheduled for 10 mins.

But if we copy the following code in the execute method, you can see that,
On the first time, it will take 20 minutes to finish.
On the second time, it will take 15 minutes to finish.

In between there won't be next schedule starts after 10 mins over.

   var startTime = DateTime.UtcNow;

            if (count == 1)
            {
                while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(20))
                {
                    // Execute your loop here...
                }
            }
            else if (count > 1)
            {
                while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(15))
                {
                    // Execute your loop here...
                }
            }
            count++;

Best Answer

What is happening in you case is that during first long 30 seconds execution of the job Quartz schedules three other executions. That is why after long execution so see three short executions. They are not executed at the same time. One after another but with no delay. That is how Quartz was designed.

[DisallowConcurrentExecution]
public class HelloJob : IJob
{
    public static int count = 1;
    public void Execute(IJobExecutionContext context)
    {
        Console.WriteLine("HelloJob strted On." + DateTime.UtcNow.Ticks);
        if (count == 1)
            Thread.Sleep(TimeSpan.FromSeconds(30));

        Interlocked.Increment(ref count);
    }
}

And the output:

Ctrl+C to exit.
HelloJob strted On.636280218500144776
HelloJob strted On.636280218800201691
HelloJob strted On.636280218800211705
HelloJob strted On.636280218800222083
HelloJob strted On.636280218900009629
HelloJob strted On.636280219000000490

See, the timestamp is different and next starts after first is completed.

If you want to avoid such behavior you should either increase delay between jobs or as @BrunoFerreira suggested handle this job's schedule manually.