/// <summary> /// Initializes the job execution context with given scheduler and bundle. /// </summary> /// <param name="sched">The scheduler.</param> /// <param name="firedBundle">The bundle offired triggers.</param> public virtual void Initialize(SchedulerScheduler sched, TriggerFiredBundle firedBundle) { qs = sched; IJob job; JobDetail jobDetail = firedBundle.JobDetail; try { job = sched.JobFactory.NewJob(firedBundle); } catch (SchedulerException se) { sched.NotifySchedulerListenersError(string.Format(CultureInfo.InvariantCulture, "An error occured instantiating job to be executed. job= '{0}'", jobDetail.FullName), se); throw; } catch (Exception e) { SchedulerException se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Problem instantiating type '{0}'", jobDetail.JobType.FullName), e); sched.NotifySchedulerListenersError(string.Format(CultureInfo.InvariantCulture, "An error occured instantiating job to be executed. job= '{0}'", jobDetail.FullName), se); throw se; } jec = new JobExecutionContext(scheduler, firedBundle, job); }
/// <summary> /// Create a JobExcecutionContext with the given context data. /// </summary> public JobExecutionContext(IScheduler scheduler, TriggerFiredBundle firedBundle, IJob job) { this.scheduler = scheduler; trigger = firedBundle.Trigger; calendar = firedBundle.Calendar; jobDetail = firedBundle.JobDetail; this.job = job; recovering = firedBundle.Recovering; fireTimeUtc = firedBundle.FireTimeUtc; scheduledFireTimeUtc = firedBundle.ScheduledFireTimeUtc; prevFireTimeUtc = firedBundle.PrevFireTimeUtc; nextFireTimeUtc = firedBundle.NextFireTimeUtc; jobDataMap = new JobDataMap(); jobDataMap.PutAll(jobDetail.JobDataMap); jobDataMap.PutAll(trigger.JobDataMap); }
/// <summary> /// Called by the scheduler at the time of the trigger firing, in order to /// produce a <see cref="IJob" /> instance on which to call Execute. /// </summary> /// <remarks> /// <p> /// It should be extremely rare for this method to throw an exception - /// basically only the the case where there is no way at all to instantiate /// and prepare the Job for execution. When the exception is thrown, the /// Scheduler will move all triggers associated with the Job into the /// <see cref="TriggerState.Error" /> state, which will require human /// intervention (e.g. an application restart after fixing whatever /// configuration problem led to the issue wih instantiating the Job. /// </p> /// </remarks> /// <param name="bundle">The TriggerFiredBundle from which the <see cref="JobDetail" /> /// and other info relating to the trigger firing can be obtained.</param> /// <returns>the newly instantiated Job</returns> /// <throws> SchedulerException if there is a problem instantiating the Job. </throws> public override IJob NewJob(TriggerFiredBundle bundle) { IJob job = base.NewJob(bundle); JobDataMap jobDataMap = new JobDataMap(); jobDataMap.PutAll(bundle.JobDetail.JobDataMap); jobDataMap.PutAll(bundle.Trigger.JobDataMap); SetObjectProperties(job, jobDataMap); return job; }
/// <summary> /// Inform the <see cref="IJobStore" /> that the scheduler is now firing the /// given <see cref="Trigger" /> (executing its associated <see cref="IJob" />), /// that it had previously acquired (reserved). /// </summary> public virtual TriggerFiredBundle TriggerFired(SchedulingContext ctxt, Trigger trigger) { lock (triggerLock) { TriggerWrapper tw = (TriggerWrapper) triggersByFQN[TriggerWrapper.GetTriggerNameKey(trigger)]; // was the trigger deleted since being acquired? if (tw == null || tw.trigger == null) { return null; } // was the trigger completed, paused, blocked, etc. since being acquired? if (tw.state != InternalTriggerState.Acquired) { return null; } ICalendar cal = null; if (tw.trigger.CalendarName != null) { cal = RetrieveCalendar(ctxt, tw.trigger.CalendarName); if (cal == null) { return null; } } NullableDateTime prevFireTime = trigger.GetPreviousFireTimeUtc(); // in case trigger was replaced between acquiring and firering timeTriggers.Remove(tw); // call triggered on our copy, and the scheduler's copy tw.trigger.Triggered(cal); trigger.Triggered(cal); //tw.state = TriggerWrapper.StateExecuting; tw.state = InternalTriggerState.Waiting; TriggerFiredBundle bndle = new TriggerFiredBundle(RetrieveJob(ctxt, trigger.JobName, trigger.JobGroup), trigger, cal, false, DateTime.UtcNow, trigger.GetPreviousFireTimeUtc(), prevFireTime, trigger.GetNextFireTimeUtc()); JobDetail job = bndle.JobDetail; if (job.Stateful) { ArrayList trigs = GetTriggerWrappersForJob(job.Name, job.Group); IEnumerator itr = trigs.GetEnumerator(); while (itr.MoveNext()) { TriggerWrapper ttw = (TriggerWrapper) itr.Current; if (ttw.state == InternalTriggerState.Waiting) { ttw.state = InternalTriggerState.Blocked; } if (ttw.state == InternalTriggerState.Paused) { ttw.state = InternalTriggerState.PausedAndBlocked; } timeTriggers.Remove(ttw); } blockedJobs.Add(JobWrapper.GetJobNameKey(job)); } else { NullableDateTime d = tw.trigger.GetNextFireTimeUtc(); if (d.HasValue) { lock (triggerLock) { timeTriggers.Add(tw); } } } return bndle; } }
/// <summary> /// Trigger retry loop that is executed on error condition. /// </summary> /// <param name="bndle">The bndle.</param> public virtual void ErrorTriggerRetryLoop(TriggerFiredBundle bndle) { int retryCount = 0; try { while (!halted) { try { Thread.Sleep(DbFailureRetryInterval); // retry every N seconds (the db connection must be failed) retryCount++; qsRsrcs.JobStore.TriggeredJobComplete(ctxt, bndle.Trigger, bndle.JobDetail, SchedulerInstruction.SetAllJobTriggersError); retryCount = 0; break; } catch (JobPersistenceException jpe) { if (retryCount%4 == 0) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while releasing trigger '{0}'", bndle.Trigger.FullName), jpe); } } catch (ThreadInterruptedException e) { Log.Error(string.Format(CultureInfo.InvariantCulture, "ReleaseTriggerRetryLoop: InterruptedException {0}", e.Message), e); } catch (Exception e) { Log.Error(string.Format(CultureInfo.InvariantCulture, "ReleaseTriggerRetryLoop: Exception {0}", e.Message), e); } } } finally { if (retryCount == 0) { Log.Info("ReleaseTriggerRetryLoop: connection restored."); } } }