2

我有一个项目,我使用TopShelfTopShelf.Quartz

按照这个例子,我正在建立我的工作

                s.ScheduleQuartzJob(q =>
                    q.WithJob(() => JobBuilder.Create<MyJob>().Build())
                    .AddTrigger(() => TriggerBuilder.Create()
                        .WithSimpleSchedule(builder => builder
                            .WithIntervalInSeconds(5)
                            .RepeatForever())
                        .Build())
                );

即使前一个仍在运行,它也会每五秒触发一次我的工作。我真正想要实现的是开始工作,完成后等待五秒钟,然后重新开始。这是可能的还是我必须实现自己的逻辑(例如通过静态变量)。

4

4 回答 4

5

@NateKerkhofs 提出的工作监听器将起作用,如下所示:

public class RepeatAfterCompletionJobListener : IJobListener
{
    private readonly TimeSpan interval;

    public RepeatAfterCompletionJobListener(TimeSpan interval)
    {
        this.interval = interval;
    }

    public void JobExecutionVetoed(IJobExecutionContext context)
    {
    }

    public void JobToBeExecuted(IJobExecutionContext context)
    {
    }

    public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
    {
       string triggerKey = context.JobDetail.Key.Name + ".trigger";

        var trigger = TriggerBuilder.Create()
                .WithIdentity(triggerKey)
                .StartAt(new DateTimeOffset(DateTime.UtcNow.Add(interval)))
                .Build();

        context.Scheduler.RescheduleJob(new TriggerKey(triggerKey), trigger);
    }

    public string Name
    {
        get
        {
            return "RepeatAfterCompletionJobListener";
        }
    }
}

然后将监听器添加到调度器中:

var jobKey = "myJobKey";
var schedule = new StdSchedulerFactory().GetScheduler();
listener = new
   RepeatAfterCompletionJobListener(TimeSpan.FromSeconds(5));

schedule.ListenerManager.AddJobListener
         (listener, KeyMatcher<JobKey>.KeyEquals(new JobKey(jobKey)));

var job = JobBuilder.Create(MyJob)
                .WithIdentity(jobKey)
                .Build();

// Schedule the job to start in 5 seconds to give the service time to initialise
var trigger = TriggerBuilder.Create()
                .WithIdentity(CreateTriggerKey(jobKey))
                .StartAt(DateTimeOffset.Now.AddSeconds(5))
                .Build();

schedule.ScheduleJob(job, trigger);

不幸的是,我不知道如何使用 Typshelf.Quartz 库使用的流畅语法来做到这一点(或者是否可以做到),我将它与 TopShelf 和常规 Quartz.Net 一起使用。

于 2014-09-19T23:48:02.187 回答
4

您可以使用 TriggerListener ( http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/trigger-and-job-listeners.html ) 来监听触发器何时完成,然后重新安排在 5秒。

另一种选择是将下一个作业安排为作业本身的执行中的最终操作。

http://www.quartz-scheduler.net/documentation/faq.html在 2/3 的地方有一个问题,解释了更多关于它的问题。

于 2014-09-19T09:41:11.130 回答
3

JobListener 解决方案是一种非常强大且灵活的方式,可以在完成后重新安排您的工作。感谢 Nate Kerkhofs 和 stuartd 的投入。

就我而言,用属性装饰我的 Job 类就足够了,DisallowConcurrentExecution因为我的工作没有不同的实例

[DisallowConcurrentExecution]
public class MyJob : IJob
{
}

仅供参考:在代码中使用 JobListerenerTopShelf.Quartz可能如下所示

var jobName = "MyJob";
var jobKey = new JobKey(jobName);

s.ScheduleQuartzJob(q =>
           q.WithJob(() => JobBuilder.Create<MyJob>()
                .WithIdentity(jobKey).Build())
            .AddTrigger(() => TriggerBuilder.Create()
                .WithSimpleSchedule(builder => builder
                    .WithIntervalInSeconds(5)
                .Build())

var listener = new RepeatAfterCompletionJobListener(TimeSpan.FromSeconds(5));
var listenerManager = ScheduleJobServiceConfiguratorExtensions
      .SchedulerFactory().ListenerManager;
listenerManager.AddJobListener(listener, KeyMatcher<JobKey>.KeyEquals(jobKey));

如果您正在使用TopShelf.Quartz.Ninject(像我一样)不要忘记在打电话UseQuartzNinject()之前打电话ScheduleJobServiceConfiguratorExtensions.SchedulerFactory()

于 2014-09-23T06:27:56.670 回答
1

我发现最好的方法是添加简单的 Job Listener。在我的示例中,它会在失败后重新安排工作。当然,您可以添加延迟.StartAt(DateTime.UtcNow)

public class QuartzRetryJobListner : IJobListener
{
    public string Name => GetType().Name;
    public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default) => await Task.CompletedTask;
    public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default) => await Task.CompletedTask;


    public async Task JobWasExecuted(
        IJobExecutionContext context,
        JobExecutionException jobException,
        CancellationToken cancellationToken = default)
    {
        if (jobException == null) return;

        // Create and schedule new trigger
        ITrigger retryTrigger = TriggerBuilder.Create()
             .StartAt(DateTime.UtcNow)
             .Build();

        await context.Scheduler.ScheduleJob(context.JobDetail, new[] { retryTrigger }, true);
    }
}

另外,我认为添加类扩展很有用

public static class QuartzExtensions
{
    public static void RepeatJobAfterFall(this IScheduler scheduler, IJobDetail job)
    {
        scheduler.ListenerManager.AddJobListener(
            new QuartzRetryJobListner(),
            KeyMatcher<JobKey>.KeyEquals(job.Key));
    }
}

只是为了简化使用。

_scheduler.ScheduleJob(job, trigger);
//In case of failue repeat job immediately
_scheduler.RepeatJobAfterFall(job);
于 2019-04-04T07:17:45.653 回答