Quartz .Net resume after application restart - quartz-scheduler

I have quartz working with MS SQL, it stores all the job detail in sql but I don't know how to set it up to resume all the jobs after application restart.
can anyone please let me know how setup quartz to resume jobs after application restart.
This is what I do to schedule a job on api call
File.AppendAllText(#"C:\Temp\test.txt",$"Starting sechd at {DateTime.Now.ToString("ddMMyyyyHHmmss")}");
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler sc = sf.GetScheduler();
sc.Start();
IJobDetail emailJob = JobBuilder.Create<EmailJob>()
.WithIdentity("reportemail", "reportgroup")
.Build();
string dom = js.DayOfMonth.ToString();
if (js.DayOfWeek > 0)
dom = "?";
string dow = (js.DayOfWeek < 1) ? "*" : js.DayOfWeek.ToString();
string y = (js.Year > 0) ? js.Year.ToString() : "*";
string m = (js.Month > 0) ? js.Month.ToString() : "*";
string crn = $"{js.Second.ToString()} {js.Minute.ToString()} {js.Hour.ToString()} {dom} {m} {dow} {y}";
ITrigger trigger = TriggerBuilder.Create()
.ForJob(emailJob)
.WithIdentity("reporttrigger","reportgroup")
.WithCronSchedule("0 0/3 * ? * *")
.StartNow()
.Build();
sc.ScheduleJob(emailJob, trigger);
Thanks

Im currently using Quartz.Net in my MVC application, and what I have done is in my JobScheducler.cs I have a method called "Start" where I have placed all the code, for the schedules I want to be run on application start.
In Global.asax I have instantiated the JobScheduler and I then call the start method, which in turn. Starts all of the schedules I've set up to be run.

Related

How can I run crone Trigger immediately using crone expression in java?

Below is my code, I want to run my job every ten minutes by crone expression.
I want the first time my job run immediately after that it should run on 10 minutes interval.I am using quartz-2.1.2
JobKey jobKeyA = new JobKey("abc", "abc");
JobDetail jobA = JobBuilder.newJob(ContiniousJob.class)
.withIdentity(jobKeyA).build();
Trigger trigger3 = TriggerBuilder
.newTrigger()
.withIdentity("abc", "abc")
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/10 * * * ?"))
.build();
Thanks.
You don't need CronTrigger if you just want 10 minutes interval, you can just use SimpleTrigger:
Trigger trigger3 = TriggerBuilder
.newTrigger()
.withIdentity("abc", "abc")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInMinutes(10)
.repeatForever())
.build();
If you still need to use CronTrigger for any reason, this should work:
// Trigger to run immediately
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("abc", "abc")
.startNow()
.build();
Set<Trigger> triggers = new HashSet<>();
triggers.add(trigger);
// Your CronTrigger
Date delayedStart = DateUtils.addMinutes(new Date(), 10);
Trigger cronTrigger = TriggerBuilder
.newTrigger()
.withIdentity("abc", "abc")
.startAt(delayedStart)
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/10 * * * ?"))
.build();
triggers.add(cronTrigger);
// Schedule job with multiple triggers
scheduler.scheduleJob(job, triggers, false);
One trigger to run immediately, another one to be your CronTrigger.
Unfortunately, there is no chances to fire cron rightaway.I have suggestion to schedule task right after when it needs to be launched with a some short delay period (current time + 1 minute).
Try to test your expression here.

Prevent Quartz job recovery from starting on long-runnng tasks

I'm building Quartz jobs with the RequestRecovery flag set, because I have multiple server instances running and if one fails while running a job, I'd like another instance to pick up that job and restart it.
IJobDetail job = JobBuilder.Create<SystemMaintenance>()
.WithIdentity("SystemMaintenance", "SystemMaintenance")
.RequestRecovery(true)
.WithDescription("System task that runs every 6 hours")
.Build();
However, what I've noticed is that if the job is running for a very long time (say over 10 minutes), the other instances will start running the job because they assume that it has failed, even though it is running fine.
Is there any way that I can periodically ping Quartz, perhaps through JobExecutionContext, to let it know that a specific instance is still running and processing a job, to prevent others from assuming failure and starting it?
EDIT:
My configuration looks like this:
NameValueCollection properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "Scheduler";
properties["quartz.scheduler.instanceId"] = "AUTO";
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "5";
properties["quartz.threadPool.threadPriority"] = "Normal";
properties["quartz.jobStore.misfireThreshold"] = "60000";
properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz";
properties["quartz.jobStore.useProperties"] = "true";
properties["quartz.jobStore.dataSource"] = "default";
properties["quartz.jobStore.tablePrefix"] = "QRTZ_";
properties["quartz.jobStore.clustered"] = "true";
properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz";
properties["quartz.dataSource.default.connectionString"] = ConnectionStringService.DatabaseConnectionString;
properties["quartz.dataSource.default.provider"] = "SqlServer-20";

Schedule task to run everyday at specific time with Quartz.NET

I am using Quartz.NET for doing a task everyday at specific hour and this is my code:
public class TestSchedule : ISchedule
{
public void Run()
{
DateTimeOffset startTime = DateBuilder.FutureDate(2, IntervalUnit.Second);
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1")
.StartAt(startTime)
.WithDailyTimeIntervalSchedule(x => x.OnEveryDay().StartingDailyAt(new TimeOfDay(7, 0)).WithRepeatCount(0))
.Build();
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler sc = sf.GetScheduler();
sc.ScheduleJob(job, trigger);
sc.Start();
}
}
my code is working, but problem is that works only once(it seems that , it's because WithRepeatCount(0) )
now, how can say that run everyday at 7 o'clock?
PS : I don't want use CronTrigger to do that.
DailyTimeIntervalTriggerImpl only support repeatCount.
This trigger also supports "repeatCount" feature to end the trigger
fire time after a certain number of count is reached. Just as the
SimpleTrigger, setting repeatCount=0 means trigger will fire once
only! Setting any positive count then the trigger will repeat count +
1 times. Unlike SimpleTrigger, the default value of repeatCount of
this trigger is set to REPEAT_INDEFINITELY instead of 0 though.
Cron expressions are beautiful and there's loads of tools which can help you to achieve what you're looking for.
Another alternative would be to use a SimpleTriggerImpl and set the interval every 24 hours:
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1")
.StartAt(startTime)
.WithSimpleSchedule(x => x.RepeatForever().WithIntervalInHours(24))
.Build();

Quartz with couple of jobs but only one running

I have quartz schedule with couple of jobs but only one (1st one) is running. Even if I try to force the second job to run it doesn't.
// The Quartz Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
JobDetailImpl jobDetail = new JobDetailImpl();
jobDetail.setJobClass(SchedulerJob.class);
jobDetail.setName("4HR");
jobDetail.setGroup("G");
// Initiate CronTrigger with its name and group name
CronTriggerImpl cronTrigger = new CronTriggerImpl();
cronTrigger.setName("4HR");
cronTrigger.setGroup("G");
// setup CronExpression
String CRON_EXPRESSION = "0 0 0/4 * * ?"; // fire every 4 hours
CronExpression cexp = new CronExpression(CRON_EXPRESSION);
// Assign the CronExpression to CronTrigger
cronTrigger.setCronExpression(cexp);
// schedule a job with JobDetail and Trigger
scheduler.scheduleJob(jobDetail, cronTrigger);
JobDetailImpl oneHRJob = new JobDetailImpl();
oneHRJob.setJobClass(Run1HRSchdule.class);
oneHRJob.setName("Job1HR");
oneHRJob.setGroup("G");
CronTriggerImpl oneHRTrigger = new CronTriggerImpl();
oneHRTrigger.setName("Trigger1HR");
oneHRTrigger.setGroup("G");
// Assign the CronExpression to CronTrigger
String CRON_EXPRESSION_1HR = "0 0 0/1 * * ?"; // fire every 1 hour
oneHRTrigger.setCronExpression( new CronExpression(CRON_EXPRESSION_1HR) );
// schedule a job with JobDetail and Trigger
scheduler.scheduleJob(oneHRJob, oneHRTrigger);
// start the scheduler
System.out.println ("Starting Scheduler");
scheduler.start();
System.out.println ("Scheduler started:" + scheduler.isStarted() );
scheduler.triggerJob( oneHRJob.getKey() );
I have tried changing the cron expression but hasn't helped.
What could I be doing wrong?

Microsoft Robotics and Sql

I have an issue implementing CCR with SQL. It seems that when I step through my code the updates and inserts I am trying to execute work great. But when I run through my interface without any breakpoints, it seems to be working and it shows the inserts, updates, but at the end of the run, nothing got updated to the database.
I proceeded to add a pause to my code every time I pull anew thread from my pool and it works... but that defeats the purpose of async coding right? I want my interface to be faster, not slow it down...
Any suggestions... here is part of my code:
I use two helper classes to set my ports and get a response back...
/// <summary>
/// Gets the Reader, requires connection to be managed
/// </summary>
public static PortSet<Int32, Exception> GetReader(SqlCommand sqlCommand)
{
Port<Int32> portResponse = null;
Port<Exception> portException = null;
GetReaderResponse(sqlCommand, ref portResponse, ref portException);
return new PortSet<Int32, Exception>(portResponse, portException);
}
// Wrapper for SqlCommand's GetResponse
public static void GetReaderResponse(SqlCommand sqlCom,
ref Port<Int32> portResponse, ref Port<Exception> portException)
{
EnsurePortsExist(ref portResponse, ref portException);
sqlCom.BeginExecuteNonQuery(ApmResultToCcrResultFactory.Create(
portResponse, portException,
delegate(IAsyncResult ar) { return sqlCom.EndExecuteNonQuery(ar); }), null);
}
then I do something like this to queue up my calls...
DispatcherQueue queue = CreateDispatcher();
String[] commands = new String[2];
Int32 result = 0;
commands[0] = "exec someupdateStoredProcedure";
commands[1] = "exec someInsertStoredProcedure '" + Settings.Default.RunDate.ToString() + "'";
for (Int32 i = 0; i < commands.Length; i++)
{
using (SqlConnection connSP = new SqlConnection(Settings.Default.nbfConn + ";MultipleActiveResultSets=true;Async=true"))
using (SqlCommand cmdSP = new SqlCommand())
{
connSP.Open();
cmdSP.Connection = connSP;
cmdSP.CommandTimeout = 150;
cmdSP.CommandText = "set arithabort on; " + commands[i];
Arbiter.Activate(queue, Arbiter.Choice(ApmToCcrAdapters.GetReader(cmdSP),
delegate(Int32 reader) { result = reader; },
delegate(Exception e) { result = 0; throw new Exception(e.Message); }));
}
}
where ApmToCcrAdapters is the class name where my helper methods are...
The problem is when I pause my code right after the call to Arbiter.Activate and I check my database, everything looks fine... if I get rid of the pause ad run my code through, nothing happens to the database, and no exceptions are thrown either...
The problem here is that you are calling Arbiter.Activate in the scope of your two using blocks. Don't forget that the CCR task you create is queued and the current thread continues... right past the scope of the using blocks. You've created a race condition, because the Choice must execute before connSP and cmdSP are disposed and that's only going to happen when you're interfering with the thread timings, as you have observed when debugging.
If instead you were to deal with disposal manually in the handler delegates for the Choice, this problem would no longer occur, however this makes for brittle code where it's easy to overlook disposal.
I'd recommend implementing the CCR iterator pattern and collecting results with a MulitpleItemReceive so that you can keep your using statements. It makes for cleaner code. Off the top of my head it would look something like this:
private IEnumerator<ITask> QueryIterator(
string command,
PortSet<Int32,Exception> resultPort)
{
using (SqlConnection connSP =
new SqlConnection(Settings.Default.nbfConn
+ ";MultipleActiveResultSets=true;Async=true"))
using (SqlCommand cmdSP = new SqlCommand())
{
Int32 result = 0;
connSP.Open();
cmdSP.Connection = connSP;
cmdSP.CommandTimeout = 150;
cmdSP.CommandText = "set arithabort on; " + commands[i];
yield return Arbiter.Choice(ApmToCcrAdapters.GetReader(cmdSP),
delegate(Int32 reader) { resultPort.Post(reader); },
delegate(Exception e) { resultPort.Post(e); });
}
}
and you could use it something like this:
var resultPort=new PortSet<Int32,Exception>();
foreach(var command in commands)
{
Arbiter.Activate(queue,
Arbiter.FromIteratorHandler(()=>QueryIterator(command,resultPort))
);
}
Arbiter.Activate(queue,
Arbiter.MultipleItemReceive(
resultPort,
commands.Count(),
(results,exceptions)=>{
//everything is done and you've got 2
//collections here, results and exceptions
//to process as you want
}
)
);