【问题标题】:In Quartz.net, run one instance of a job at a time在 Quartz.net 中,一次运行一个作业实例
【发布时间】:2017-04-17 08:56:12
【问题描述】:

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

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 秒。然后我删除了断点并执行了代码,根据我的预期,应该只执行一次以进行另一次尝试。

但是execute方法在另一个内执行了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);
    }
}

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

解决方案

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

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

【问题讨论】:

  • 您是否尝试在不附加调试器的情况下执行?只是写日志?也许调试器会影响行为。
  • 我想运行执行超过 10 秒。所以我尝试了调试器。
  • 尝试使用Thread.Sleep而不是调试器来确认问题。调试器会影响执行。
  • 我试过threed.sleep但没有帮助。

标签: c# quartz.net


【解决方案1】:

在您的情况下发生的情况是,在作业 Quartz 的第一个长 30 秒执行期间,会安排其他三个执行。这就是为什么在长时间处决之后看到三个短期处决。它们同时执行。一个接一个,但没有延迟。这就是 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 的建议手动处理此作业的时间表。

【讨论】:

  • 不是这样写的,就像总是线程休眠 30 秒一样。检查我更新的 hellojob 课程。第一次运行 30 秒,后续调用运行 10 秒。 30秒后,10秒内连续运行3次
  • 您甚至可以将下一个延迟设置为 2-3 秒,以确保它们不会同时执行。
  • @JeevaJsb,它回答了你的问题吗?
  • 谢谢,我会检查.. 我们真的需要 Interlocked.Increment(ref count);与计数..什么是联锁的?是用石英设计的吗?
  • 感谢您的关心和帮助。欢呼我们没有必要去联锁。下一个计划开始仅完成上一个作业计划。
【解决方案2】:

几天前我也遇到了同样的问题。结果是我不得不取消安排工作,这是触发器。 当我的应用程序结束时,我正在使用此方法。

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

希望对你有所帮助。

【讨论】:

  • 我不明白你的流程。什么时候取消我所有的工作,为什么?如果我取消计划,计划何时开始?
  • 不,您必须在应用程序结束时取消计划。就我而言,我在 Windows 服务中使用作业,因此当服务停止时,我必须取消安排作业。如果我不这样做,下一次服务启动时,我有两倍的作业运行实例。
  • 为什么不在 OnStop Windows 服务中只使用 scheduler.Shutdown(false/true);
【解决方案3】:

只要使用这样的东西:

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

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

我们有一些工作,这很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多