Quartz.Net Trigger Scheduled Job On Demand - quartz.net

I have some Quartz.Net jobs which are running on a Schedule
scheduler.ScheduleJob(
new JobDetailImpl("MarkAsSolutionReminderJob", typeof(MarkAsSolutionReminderJob)),
new CalendarIntervalTriggerImpl("MarkAsSolutionReminderJobTrigger", IntervalUnit.Hour, 6));
Is it possible for me to manually trigger this Job to run when I want it to?
So it continues to run as normal, but in a specific piece of code I might want to just run it out of schedule once or twice. But it doesn't affect the scheduled job?

Is it possible for me to manually trigger this Job to run when I want it to?
Yes, you can trigger this job as and when you need.
Use void TriggerJob(JobKey jobKey) method for this as below:
scheduler.TriggerJob(new Jobkey("MarkAsSolutionReminderJob"));
If you want to pass some data to the job while executing it on demand, you can also do that by just using another overload void TriggerJob(JobKey jobKey, JobDataMap data); of the same method as below:
Dictionary<string, string> data = new Dictionary<string, string>();
//populate dictionary as per your needs
JobDataMap jobData = new JobDataMap(data);
scheduler.TriggerJob(new Jobkey("MarkAsSolutionReminderJob"),jobData);

Related

How to prevent Quartz.Net misfired job from retrying

I know I can specify .WithMisfireHandlingInstructionDoNothing() when building the trigger but some of my jobs are triggered via the IScheduler.TriggerJob() method, so without any triggers.
I can detect and log misfires in the ITriggerListener listener but how can I stop Quartz from trying to fire the job again? If I understand correctly .VetoJobExecution is not usable since the job has to be triggered successfully anyway.
Any other ideas?
Edit: my implementation
JobDataMap jobData = new JobDataMap(data);
IJobDetail jobTemplate = await jobScheduler.GetJobDetail(jobKey);
var jobTrigger = TriggerBuilder.Create()
.ForJob(jobTemplate)
.UsingJobData(jobData)
.WithSimpleSchedule(s => s.WithRepeatCount(0).WithMisfireHandlingInstructionNextWithRemainingCount())
.StartNow()
.Build();
await jobScheduler.ScheduleJob(jobTrigger);
Well if you just want the TriggerJob behavior you can achieve that just by adding one simple trigger to scheduler that is going to trigger immediately and configure retry policy for that. So if you can change the call sites of TriggerJob to create a simple trigger instead (maybe an extension method that allows to define the policy), the Quartz source for TriggerJob is here.
I think I've got it.
You have to use the WithMisfireHandlingInstructionNextWithRemainingCount policy, and WithRepeatCount(0).
But the trick here is to set the right value in the IScheduler MisfireThreshold to the misfire to be considered as a real misfire. I mean, if your misfire threshold is set to 60 seconds (default) then any job not executed in less than 60 seconds from schedule, will NOT be considered as a misfire. And so, the misfire policy will not be used.
In my case, with 3 second duration jobs, I had to set the WithMisfireThreshold to 1 second or less.
This way, the job is not retried if "really misfired".

JSR 352: Is there a way to tell if a particular job execution is a restart or not from within a job?

I know how to get the Execution Id and Instance Id of a job using the Job Context. But if i restart a job, is there way to know if the job execution is the first execution or a restart within the job, for instance inside the reader?
No, but there is an open issue asking for that:
https://java.net/bugzilla/show_bug.cgi?id=7473
This is a bit overly complicated (as the other answer noted, there's an issue opened to consider enhancement for the future Batch 1.1).
You could do this:
//
// Assumes JobContext injected into 'jobCtx' field
//
private boolean isRestart() {
JobOperator jo = BatchRuntime.getJobOperator();
JobInstance jobInstance = jo.getJobInstance(jobCtx.getExecutionId());
int numExecutions = jo.getJobExecutions(jobInstance).size();
return numExecutions > 1;
}

Quartz.net scheduler

We have installed quartz.net scheduler service and configured a (memory)job to run daily # 10 pm. In case the server hosting this service is restarted, is there a way to force the job to run as soon as the service comes up? In normal scenario job should fire at 10pm as scheduled, but whenever the server/service is restarted, we want the job to run immediately even if it is not scheduled to run at that time. If there's some configuration value to achieve this, that would be the best option.
Write a little code that reads a small xml file (custom one of your own doing)....
and put it in your startup code.
foreach( xmlElement in yourXmlFile)
{
string someJobName= ""; /* read xml for jobName */
String someJobGroup= ""; /* read xml for job group name */
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(someJobName, someJobGroup)
.startNow()
.build();
}
You can perform this with the help of WithMisfireHandlingInstructionFireAndProceed method of CronScheduleBuilder as shown below:
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSchedule(CronScheduleBuilder
.WeeklyOnDayAndHourAndMinute(DayOfWeek.Monday, 09, 00)
.WithMisfireHandlingInstructionFireAndProceed()
//MISFIRE_INSTRUCTION_FIRE_NOW
.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time"))
)
//.ForJob(myJobKey)
.Build();
scheduler.ScheduleJob(job, trigger);

Update args of a scheduled job

I have scheduled a job
Worker.perform_at(time, args)
And I can fetch the scheduled jobs
job = Sidekiq::ScheduledSet.new.find_job(jid)
job.args # this is the args I passed above
I need to update the args that will be passed to the worker when it is called, i.e. update job.args. How do I do that?
This won't work:
job.args = new_args
Sidekiq::ScheduledSet.new.to_a[0] = job
Well update the task is not the way achieving it cancel job and create new with new args:
job = Sidekiq::ScheduledSet.new.find_job(jid)
## time = job.time // Or just set time needed.
Sidekiq::Status.cancel jid
Worker.perform_at(time, new_args)
it will also make it easier for you to debug and log the jobs because when you edit/update them on the fly could cause bugs that very hard to identify.

Executing Quartz.NET jobs from a Windows Service

I got a ASP.NET MVC 4 web application and quartz.net running as a windows service and common logging configured according to these sources :
http://geekswithblogs.net/TarunArora/archive/2012/11/16/install-quartz.net-as-a-windows-service-and-test-installation.aspx
http://geekswithblogs.net/TarunArora/archive/2012/11/17/quartz.net-windows-service-configure-logging.aspx
and with this code in Global.asax in place:
var properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "ServerScheduler";
// set thread pool info
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "5";
properties["quartz.threadPool.threadPriority"] = "Normal";
// set remoting expoter
properties["quartz.scheduler.proxy"] = "true";
properties["quartz.scheduler.proxy.address"] = "tcp://localhost:555/QuartzScheduler";
// construct a scheduler factory
ISchedulerFactory schedFact = new StdSchedulerFactory(properties);
// get a scheduler
IScheduler sched = schedFact.GetScheduler();
sched.Start();
IJobDetail jobDetail = JobBuilder.Create<SimpleJob>()
.WithIdentity("simpleJob", "simpleJobs")
.RequestRecovery()
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("simpleTrigger", "simpleTriggers")
.StartNow()
.WithSimpleSchedule(x => x.WithRepeatCount(4).WithIntervalInSeconds(10))
.Build();
sched.ScheduleJob(jobDetail, trigger);
and the job:
public class SimpleJob : IJob
{
public SimpleJob()
{
}
public void Execute(IJobExecutionContext context)
{
Debug.WriteLine("I Executed at " + DateTime.Now.ToString());
}
}
and now if I run the app the log produces something like this 5 times
19:35:23 [ServerScheduler_QuartzSchedulerThread] DEBUG Quartz.Core.QuartzSchedulerThread - Batch acquisition of 1 triggers
19:35:23 [ServerScheduler_QuartzSchedulerThread] DEBUG Quartz.Simpl.SimpleJobFactory - Producing instance of Job 'simpleJobs.simpleJob', class=Navigate.Quartz.Jobs.SimpleJob
19:35:23 [ServerScheduler_QuartzSchedulerThread] DEBUG Quartz.Core.QuartzSchedulerThread - Batch acquisition of 1 triggers
19:35:23 [ServerScheduler_Worker-1] DEBUG Quartz.Core.JobRunShell - Calling Execute on job simpleJobs.simpleJob
19:35:23 [ServerScheduler_Worker-1] DEBUG Quartz.Core.JobRunShell - Trigger instruction : NoInstruction
Then deletes the trigger and carries on, but no job is executed and no lines are written to debug output
if I run the scheduler embedded in the app, however, by not passing the NameValueCollection to the StdSchedulerFactory
ISchedulerFactory schedFact = new StdSchedulerFactory();
everything works fine and I get the lines outputted 5 times every 10 seconds
I Executed at 28.05.2013. 19:47:48
I Executed at 28.05.2013. 19:47:58
I Executed at 28.05.2013. 19:48:08
I Executed at 28.05.2013. 19:48:18
I Executed at 28.05.2013. 19:48:28
What am I missing, why isnt the windows service actually executing the code, the service is running as Local System, nothing changes if I change it to administrator account tho. Any help will be appreciated.
Chris
I think that the service may actually be executing the code but you are not seeing the output. Try changing the Debug.WriteLine() to use Common.Logging so that the output is included in the same log that Quartz is using for its log output. For code examples see http://netcommon.sourceforge.net/docs/1.2.0/reference/html/logging.html.
I also looked at the code that we are using in our implementation, and I see that we are not doing a .Start() after .GetScheduler(). Since you are working with a service running Quartz, the scheduler should already be started, and you should just work with the scheduler that is returned from .GetScheduler(). Try removing the .Start() from your code.

Resources