I'm building a windows service which is performing a scheduled task which processes a queue of commands (from a legacy system) at a regular interval (once per min) using Quartz.net
If the task takes longer than 1 min, which would be unusual but possible under certain circumstances, I'd like it to simple ignore the triggers it missed firing.
However I can't seem to get this to happen. It does the processing and then quickly fires all the triggers it missed in quick succession. As I understand you can set a threshold for the misfires but I don't seem to be-able to get this working.
I'm using [DisallowConcurrentExecution()] on the Job to ensure only one instance of the job is running at any one time.
Below are a couple of snippets. First passing in some config info - is this how you set the misfire threshold?
NameValueCollection config = new NameValueCollection();
config.Add("quartz.jobStore.misfireThreshold", "600000");
schedFact = new StdSchedulerFactory(config);
Building a trigger with what I assume to be the correct setting of Ignore misfires:
var trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule( x => x.WithMisfireHandlingInstructionIgnoreMisfires()
.WithIntervalInSeconds(60)
.RepeatForever())
.Build();
Thoughts much appreciated.
Code for the Job: Just playing with rough ideas at this point so just running in a console app and randomly delaying a job so it shoots over the interval which is just set at 10 seconds for this. All the backed up misfires fire in quick succession after a couple of delays.
[DisallowConcurrentExecution()]
public class SomeJob : IJob
{
public SomeJob() { }
public void Execute(IJobExecutionContext context)
{
Random rnd = new Random(DateTime.UtcNow.Second);
int delay = rnd.Next(2);
Console.WriteLine("Executing Job with delay of "+ delay + " at " + DateTime.UtcNow.ToString());
if (delay == 1)
{
System.Threading.Thread.Sleep(1000 * 25); // sleep for 25 seconds
}
}
}
Example console output:
Executing Job with delay of 1 at 21/05/2015 21:27:17
Executing Job with delay of 1 at 21/05/2015 21:27:42
Executing Job with delay of 0 at 21/05/2015 21:28:07 <-- stacked misfires
Executing Job with delay of 0 at 21/05/2015 21:28:07 <--
Executing Job with delay of 0 at 21/05/2015 21:28:07 <--
Executing Job with delay of 0 at 21/05/2015 21:28:07 <--
Executing Job with delay of 0 at 21/05/2015 21:28:16
Executing Job with delay of 0 at 21/05/2015 21:28:26
Executing Job with delay of 1 at 21/05/2015 21:28:36
Executing Job with delay of 0 at 21/05/2015 21:29:01
Executing Job with delay of 0 at 21/05/2015 21:29:01
Executing Job with delay of 1 at 21/05/2015 21:29:06
WithMisfireHandlingInstructionIgnoreMisfires()
is the wrong method for what you want, it doesn't mean the job will not trigger misfires, it means it will fire all triggers that were missed as soon as possible and will then go back to ordinary schedule. Which is what you see happening.
What you need is WithMisfireHandlingInstructionNextWithRemainingCount()
. This will signal the scheduler to ignore misfires and wait for the next scheduled time.
Misfiring strategies can be a bit confusing, for a concise explanation look here (it's for the java scheduler but it doesn't matter).
Even with the right strategy, you need to understand how the misfire threshold works- if you get it wrong your misfired trigger may still fire.
From the documentation: "A misfire is the time span by which a trigger must have missed its next-fire-time, in order for it to be considered "misfired" and thus have its misfire instruction applied".
You've set the value to 600000
milliseconds (and this value is for all triggers, unfortunately there is no threshold per trigger)- the misfire strategy will only be applied if your trigger fires 600000
milliseconds after the time it should have been fired. You can lower or increase it according to your requirement.
For more about the misfire threshold, read here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With