在Quartz.net中,一次运行一个作业实例

时间:2017-04-17 08:56:13

标签: c# quartz.net

我提到了以下问题,但没有帮助我解决问题。

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

对于CronTrigger,在调度程序cs.WithMisfireHandlingInstructionDoNothing()中使用以下内容。

HelloJob中应用以下属性
DisallowConcurrentExecution

代码怎么了?
在Execute方法中,我设置了断点。根据我的代码,execute方法将在10秒内执行。

在达到第一个破发点之后,我又等了31秒。然后我根据我的期望删除了断点并执行了代码,该代码应该只执行一次以进行另一次尝试。

  

但执行方法在另一个内执行了3次(3 * 10秒)   10秒。

如何解决这个问题?

计划程序代码。

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

工作执行代码。

[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

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

解决方案

无需进行联锁或手动管理。

Quartz已经设计成只完成第一个计划,下一个计划开始。

所以我们不必担心它会同时运行。

例如(像我这样的人:-p),调度程序安排了10分钟。

但是如果我们在execute方法中复制以下代码,你可以看到, 这是第一次,需要20分钟才能完成。 第二次,需要15分钟才能完成。

介于两者之间,在10分钟后,下一个时间表开始没有。

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

3 个答案:

答案 0 :(得分:2)

在你的情况下发生的事情是,在第一个长30秒内执行作业Quartz安排其他三个执行。这就是为什么经过长时间执行所以看到三个短暂的执行。它们同时执行。一个接一个但没有延迟。这就是设计Quartz的方式。

[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);
    }
}

输出:

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

请参阅,时间戳不同,接下来在第一次完成后开始。

如果你想避免这种行为,你应该增加工作之间的延迟,或者@BrunoFerreira建议手动处理这个工作的时间表。

答案 1 :(得分:1)

我几天前遇到过同样的问题。结果我不得不安排工作和它的触发器。 我申请结束时,我正在使用这种方法。

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();
}

希望这会对你有所帮助。

答案 2 :(得分:0)

只需使用这样的东西:

        private static readonly SemaphoreSlim Lock = new SemaphoreSlim(1, 1);

        if (await Lock.WaitAsync(new TimeSpan(0, 0, 30)))
        {
           ...
        }

我们有一些工作,而且效果很好。