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

10,538

Solution 1

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.

Solution 2

I've faced the same problem a few days ago. Turn out thant I had to unschedule de job and it's trigger. I'm using this method to do so when my application ends.

private void StopAllJobs()
{
     // construct a scheduler factory
     ISchedulerFactory schedFact = new StdSchedulerFactory();
     // get a scheduler, start the schedular before triggers or anything else
     sched = schedFact.GetScheduler();
     var executingJobs = sched.GetCurrentlyExecutingJobs();
     foreach (var job in executingJobs)
     {
         sched.Interrupt(job.JobDetail.Key);
         sched.UnscheduleJob(job.Trigger.Key);
         sched.DeleteJob(job.JobDetail.Key);
     }
     sched.Clear();
}

Hope this helps you.

Share:
10,538
Jeeva J
Author by

Jeeva J

I am in the software development for the past 8 years. The area, I have worked, are asp.net, asp.net core, asp.net mvc, asp.net apis, jQuery, silverlight, angularjs, Angular, ReactJS, VueJs. My personal email address is [email protected]

Updated on June 05, 2022

Comments

  • Jeeva J
    Jeeva J almost 2 years

    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++;