I am using Quartz.net to schedule various API calls.
The API I am using restricts the number of requests that can be made per time period and if that is exceeded, then my account is penalized for the next minute (no requests can be made).
If I ever receive a notification that I have made too many requests and my account will be throttled for the next minute, I will need to ensure that no scheduled jobs fire during that period. How can I best delay firing of all scheduled jobs by a minute or two?
I was originally intending to call Scheduler.GetTriggerKeys() and loop over and update every existing trigger like so:
foreach(var triggerKey in SchedInstance.GetTriggerKeys(GroupMatcher.AnyGroup()))
{
var oldTrigger = SchedInstance.GetTrigger(triggerKey);
TriggerBuilder tb = oldTrigger.GetTriggerBuilder();
// Update the schedule associated with the builder and build the new trigger
tb.StartAt(oldTrigger.StartTimeUtc.AddSeconds(63));
var newTrigger = tb.Build();
SchedInstance.RescheduleJob(oldTrigger.Key, newTrigger);
}
Is this the right approach or would it be better to simply stop the scheduler for the same time period and then restart it?
解决方案
You have a couple of possibilities to achieve that.
As you stated, you can stop the scheduler or loop over your triggers. But this sounds for me not like the best option.
You can implement the ITriggerListener interface and use the VetoJobExecution() method. The implementation can look like this:
public class SystemThrottledTriggerListener : ITriggerListener
{
public string Name => "System Throttled Trigger Listener";
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode)
{
// no need for implementation
}
public void TriggerFired(ITrigger trigger, IJobExecutionContext context)
{
// no need for implementation
}
public void TriggerMisfired(ITrigger trigger)
{
// no need for implementation
}
public bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context)
{
// If you return true, then the Trigger is vetoed and the job is not executed.
// The Job will automatically scheduled for his next execution
return IsSystemThrottled();
}
}
Then simply add the Listener to your scheduler and all triggers are vetoed if your system is throttled:
Scheduler.ListenerManager.AddTriggerListener(new SystemThrottledTriggerListener());
You can throw a JobExecutionException to stop the execution of your job. To do this, you need to check at the beginning of the execution that your system is throttled and then throw the exeception. This is the only exception for Quartz at which you can tell Quartz that it should refire the job immediately. All other exceptions will be swallowed and will stop the execution of the job.
The implementation can look like this:
public class MyJob : IJob
{
public void Execute(IJobExecutionContext context)
{
if(IsSystemThrottled())
throw new JobExecutionException(true);
// your other stuff
}
}
If you create the exception with the parameter true, the job will immediately refired. And will refired again and again until your system is no longer throttled.
If you have many jobs, i would recommend to use a job base class that can throw the JobExecutionException and you derive your jobs only from this class.