我有一个项目,我使用TopShelf
和TopShelf.Quartz
继this example之后,我正在建立自己的工作
s.ScheduleQuartzJob(q =>
q.WithJob(() => JobBuilder.Create<MyJob>().Build())
.AddTrigger(() => TriggerBuilder.Create()
.WithSimpleSchedule(builder => builder
.WithIntervalInSeconds(5)
.RepeatForever())
.Build())
);
即使前一个仍然在运行,它每隔五秒就会激活一次。我真正想要的是开始一份工作,完成后等待五秒钟然后重新开始。这是可能的还是我必须实现自己的逻辑(例如通过静态变量)。
您可以使用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的路向下可以解释更多关于它的问题。
@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一起使用。
JobListener解决方案是一种非常强大且灵活的方式,可在完成后重新安排作业。感谢Nate Kerkhofs和stuartd的投入。
在我的情况下,使用DisallowConcurrentExecution
属性装饰我的Job类就足够了,因为我没有不同的工作实例
[DisallowConcurrentExecution]
public class MyJob : IJob
{
}
仅供参考:使用带有TopShelf.Quartz
的JobListerener,代码可能如下所示
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()
我发现的最好方法是添加简单的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);