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);
Related
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".
Im trying to retrieve the schedule of the vNext BuildDefinitions through my C# Application.
I can retrieve the BuildDefinition objects that i need.
List<BuildDefinitionReference> builddefs = buildClient.GetDefinitionsAsync().Result;
and
var buildDef = buildClient.GetFullDefinitionsAsync(project: project,
name: buildDefName).Result.ToArray();
But when looking at the BuildDefinition.Trigger information, this does not seem to contain what i need.
Simular to the XAML builds, i want to be able to read the BuildDefinition.Schedules, to see when each build is scheduled.
Who knows where this information is currently kept ?
Update:
Fixed the issue by converting the BuildTrigger to a ScheduleTrigger
if (buildDefinition.Triggers != null)
{
foreach (BuildTrigger trigger in buildDefinition.Triggers)
{
if (trigger is ScheduleTrigger)
{
ScheduleTrigger scheduleTrigger = trigger as ScheduleTrigger;
foreach (var schedule in scheduleTrigger.Schedules)
{
//Do magic
}
}
}
}
Update the Microsoft.TeamFoundationServer.ExtendedClient package to the latest version and the GetFullDefinitionsAsync method should return the schedules information, that are stored in Triggers property instead of Schedules property.
You could use Rest API to Get a build definition, a sample:
GET https://tfsserver:8080/tfs/DefaultCollection/Fabrikam-Fiber-Git/_apis/build/definitions/29?api-version=2.0
Then you will get a response as below which include trigger information:
"triggers": [
{
"schedules": [
{
"branchFilters": [
"+$/MyFirstProject/Test"
],
"timeZoneId": "UTC",
"startHours": 3,
"startMinutes": 0,
"daysToBuild": "all",
"scheduleJobId": "18316444-edbb-479d-950d-7714ba39d3d6",
"scheduleOnlyWithChanges": true
}
],
"triggerType": "schedule"
}
And the each member for your reference:
Members
branchFilters: string[].
daysToBuild: ScheduleDays. Days for a build (flags enum for days of the week)
scheduleJobId: string. The Job ID of the Scheduled job that will queue the scheduled build. Since a single trigger can have multiple
schedules and we want a single job to process a single schedule (since
each schedule has a list of branches to build), the schedule itself
needs to define the Job Id. This value will be filled in when a
definition is added or updated. The UI does not provide it or use it.
startHours: number. Local timezone hour to start
startMinutes: number. Local timezone minute to start
timeZoneId: string. Time zone of the build schedule (string representation of the time zone id)
Details please refer Schedule Rest API.
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);
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.
I am using Quartz2 Plugin, and am trying to dynamically trigger a very simple job. When the user performs a certain action, the job should be triggered some certain number of minutes in the future, and only run once.
I have tried using the simple 'schedule' method that takes a date and job data:
def sendTime = new Date()
use(groovy.time.TimeCategory) {
sendTime = sendTime + (connectionInstance.timeout).minutes
println "I will send the job at $sendTime"
}
ReportSmssyncTimeoutJob.schedule(sendTime, [connectionId:params.id])
In this setup, I find that the job actually triggers immediately instead of waiting until 'sendTime'.
My second attempt, after looking at the plugin source, was to use a SimpleTrigger
def sendTime = new Date()
use(groovy.time.TimeCategory) {
sendTime = sendTime + (connectionInstance.timeout).minutes
println "I will send the job at $sendTime"
}
// arguments here are: jobKey='test', startTime=sendTime, repeatCount=0, repeatInterval=1 (zero not allowed), job-arguments)
def trigger = TriggerHelper.simpleTrigger(new JobKey("test"), sendTime, 0, 1, [connectionId:params.id])
ReportSmssyncTimeoutJob.schedule(trigger)
In this setup, the job also triggers immediately. Is there something wrong with the SimpleTrigger implementation which prevents it from waiting until startDate?
Unfortunately, switching to the main 'quartz' plugin (which now has support for Quartz 2) is not an option as I am working on a project that has loads of jobs set up to work with the quartz2 plugin.
I asked this on the Grails mailing list and got the answer: this is a bug in the quartz2 plugin. It should be fixed in the next release (bug was noted in 0.2.3).
Update: tested this in v2.1.6.2 of the quartz2 plugin, and can confirm that both of the approaches in my question now work.