/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a non-daemon <see cref="Thread" /> /// with normal priority. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs) { Log = LogProvider.GetLogger(GetType()); //ThreadGroup generatedAux = qs.SchedulerThreadGroup; this.qs = qs; this.qsRsrcs = qsRsrcs; // start the underlying thread, but put this object into the 'paused' // state // so processing doesn't start yet... paused = true; halted = false; }
/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a <see cref="Thread" /> with the given /// attributes. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, bool setDaemon, int threadPrio) : base(qsRsrcs.ThreadName) { //ThreadGroup generatedAux = qs.SchedulerThreadGroup; this.qs = qs; this.qsRsrcs = qsRsrcs; IsBackground = setDaemon; Priority = (ThreadPriority)threadPrio; // start the underlying thread, but put this object into the 'paused' // state // so processing doesn't start yet... paused = true; halted = false; }
/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a <see cref="Thread" /> with the given /// attributes. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, bool setDaemon, int threadPrio) : base(qsRsrcs.ThreadName) { //ThreadGroup generatedAux = qs.SchedulerThreadGroup; this.qs = qs; this.qsRsrcs = qsRsrcs; IsBackground = setDaemon; Priority = (ThreadPriority) threadPrio; // start the underlying thread, but put this object into the 'paused' // state // so processing doesn't start yet... paused = true; halted = false; }
/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a <see cref="Thread" /> with the given /// attributes. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, SchedulingContext ctxt, bool setDaemon, int threadPrio) : base(qsRsrcs.ThreadName) { log = LogManager.GetLogger(GetType()); //ThreadGroup generatedAux = qs.SchedulerThreadGroup; this.qs = qs; this.qsRsrcs = qsRsrcs; this.ctxt = ctxt; IsBackground = setDaemon; Priority = (ThreadPriority)threadPrio; // start the underlying thread, but put this object into the 'paused' // state // so processing doesn't start yet... paused = true; halted = false; Start(); }
/// <summary> /// Creates a scheduler using the specified thread pool and job store and /// binds it to RMI. /// </summary> /// <param name="schedulerName">The name for the scheduler.</param> /// <param name="schedulerInstanceId">The instance ID for the scheduler.</param> /// <param name="threadPool">The thread pool for executing jobs</param> /// <param name="jobStore">The type of job store</param> /// <param name="schedulerPluginMap"></param> /// <param name="idleWaitTime">The idle wait time. You can specify TimeSpan.Zero for /// the default value, which is currently 30000 ms.</param> /// <param name="dbFailureRetryInterval">The db failure retry interval.</param> public virtual void CreateScheduler(string schedulerName, string schedulerInstanceId, IThreadPool threadPool, IJobStore jobStore, IDictionary schedulerPluginMap, TimeSpan idleWaitTime, TimeSpan dbFailureRetryInterval) { // Currently only one run-shell factory is available... IJobRunShellFactory jrsf = new StdJobRunShellFactory(); // Fire everything up // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SchedulingContext schedCtxt = new SchedulingContext(); schedCtxt.InstanceId = schedulerInstanceId; QuartzSchedulerResources qrs = new QuartzSchedulerResources(); qrs.Name = schedulerName; qrs.InstanceId = schedulerInstanceId; qrs.JobRunShellFactory = jrsf; qrs.ThreadPool = threadPool; qrs.JobStore = jobStore; // add plugins if (schedulerPluginMap != null) { foreach (ISchedulerPlugin plugin in schedulerPluginMap.Values) { qrs.AddSchedulerPlugin(plugin); } } QuartzScheduler qs = new QuartzScheduler(qrs, schedCtxt, idleWaitTime, dbFailureRetryInterval); ITypeLoadHelper cch = new CascadingClassLoadHelper(); cch.Initialize(); jobStore.Initialize(cch, qs.SchedulerSignaler); IScheduler scheduler = new StdScheduler(qs, schedCtxt); // Initialize plugins now that we have a Scheduler instance. if (schedulerPluginMap != null) { foreach (DictionaryEntry pluginEntry in schedulerPluginMap) { ((ISchedulerPlugin)pluginEntry.Value).Initialize( (string) pluginEntry.Key, scheduler); } } jrsf.Initialize(scheduler, schedCtxt); Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz scheduler '{0}", scheduler.SchedulerName)); Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz scheduler version: {0}", qs.Version)); SchedulerRepository schedRep = SchedulerRepository.Instance; qs.AddNoGCObject(schedRep); // prevents the repository from being // garbage collected schedRep.Bind(scheduler); }
/// <summary> /// The main processing loop of the <see cref="QuartzSchedulerThread" />. /// </summary> public override void Run() { bool lastAcquireFailed = false; while (!halted) { try { // check if we're supposed to pause... lock (sigLock) { while (paused && !halted) { try { // wait until togglePause(false) is called... Monitor.Wait(sigLock, 1000); } catch (ThreadInterruptedException) { } } if (halted) { break; } } int availThreadCount = qsRsrcs.ThreadPool.BlockForAvailableThreads(); if (availThreadCount > 0) // will always be true, due to semantics of blockForAvailableThreads... { IList<IOperableTrigger> triggers = null; DateTimeOffset now = SystemTime.UtcNow(); ClearSignaledSchedulingChange(); try { triggers = qsRsrcs.JobStore.AcquireNextTriggers( now + idleWaitTime, Math.Min(availThreadCount, qsRsrcs.MaxBatchSize), qsRsrcs.BatchTimeWindow); lastAcquireFailed = false; if (log.IsDebugEnabled) { log.DebugFormat("Batch acquisition of {0} triggers", (triggers == null ? 0 : triggers.Count)); } } catch (JobPersistenceException jpe) { if (!lastAcquireFailed) { qs.NotifySchedulerListenersError("An error occurred while scanning for the next trigger to fire.", jpe); } lastAcquireFailed = true; continue; } catch (Exception e) { if (!lastAcquireFailed) { Log.Error("quartzSchedulerThreadLoop: RuntimeException " + e.Message, e); } lastAcquireFailed = true; continue; } if (triggers != null && triggers.Count > 0) { now = SystemTime.UtcNow(); DateTimeOffset triggerTime = triggers[0].GetNextFireTimeUtc().Value; TimeSpan timeUntilTrigger = triggerTime - now; while (timeUntilTrigger > TimeSpan.FromMilliseconds(2)) { if (ReleaseIfScheduleChangedSignificantly(triggers, triggerTime)) { break; } lock (sigLock) { if (halted) { break; } if (!IsCandidateNewTimeEarlierWithinReason(triggerTime, false)) { try { // we could have blocked a long while // on 'synchronize', so we must recompute now = SystemTime.UtcNow(); timeUntilTrigger = triggerTime - now; if (timeUntilTrigger > TimeSpan.Zero) { Monitor.Wait(sigLock, timeUntilTrigger); } } catch (ThreadInterruptedException) { } } } if (ReleaseIfScheduleChangedSignificantly(triggers, triggerTime)) { break; } now = SystemTime.UtcNow(); timeUntilTrigger = triggerTime - now; } // this happens if releaseIfScheduleChangedSignificantly decided to release triggers if (triggers.Count == 0) { continue; } // set triggers to 'executing' IList<TriggerFiredResult> bndles = new List<TriggerFiredResult>(); bool goAhead = true; lock (sigLock) { goAhead = !halted; } if (goAhead) { try { IList<TriggerFiredResult> res = qsRsrcs.JobStore.TriggersFired(triggers); if (res != null) { bndles = res; } } catch (SchedulerException se) { qs.NotifySchedulerListenersError("An error occurred while firing triggers '" + triggers + "'", se); // QTZ-179 : a problem occurred interacting with the triggers from the db // we release them and loop again foreach (IOperableTrigger t in triggers) { qsRsrcs.JobStore.ReleaseAcquiredTrigger(t); } continue; } } for (int i = 0; i < bndles.Count; i++) { TriggerFiredResult result = bndles[i]; TriggerFiredBundle bndle = result.TriggerFiredBundle; Exception exception = result.Exception; IOperableTrigger trigger = triggers[i]; // TODO SQL exception? if (exception != null && (exception is DbException || exception.InnerException is DbException)) { Log.Error("DbException while firing trigger " + trigger, exception); qsRsrcs.JobStore.ReleaseAcquiredTrigger(trigger); continue; } // it's possible to get 'null' if the triggers was paused, // blocked, or other similar occurrences that prevent it being // fired at this time... or if the scheduler was shutdown (halted) if (bndle == null) { qsRsrcs.JobStore.ReleaseAcquiredTrigger(trigger); continue; } // TODO: improvements: // // 2- make sure we can get a job runshell before firing trigger, or // don't let that throw an exception (right now it never does, // but the signature says it can). // 3- acquire more triggers at a time (based on num threads available?) JobRunShell shell = null; try { shell = qsRsrcs.JobRunShellFactory.CreateJobRunShell(bndle); shell.Initialize(qs); } catch (SchedulerException) { qsRsrcs.JobStore.TriggeredJobComplete(trigger, bndle.JobDetail, SchedulerInstruction.SetAllJobTriggersError); continue; } if (qsRsrcs.ThreadPool.RunInThread(shell) == false) { // this case should never happen, as it is indicative of the // scheduler being shutdown or a bug in the thread pool or // a thread pool being used concurrently - which the docs // say not to do... Log.Error("ThreadPool.runInThread() return false!"); qsRsrcs.JobStore.TriggeredJobComplete(trigger, bndle.JobDetail, SchedulerInstruction.SetAllJobTriggersError); } } continue; // while (!halted) } } else // if(availThreadCount > 0) { // should never happen, if threadPool.blockForAvailableThreads() follows contract continue; // while (!halted) } DateTimeOffset utcNow = SystemTime.UtcNow(); DateTimeOffset waitTime = utcNow.Add(GetRandomizedIdleWaitTime()); TimeSpan timeUntilContinue = waitTime - utcNow; lock (sigLock) { if (!halted) { try { // QTZ-336 A job might have been completed in the mean time and we might have // missed the scheduled changed signal by not waiting for the notify() yet // Check that before waiting for too long in case this very job needs to be // scheduled very soon if (!IsScheduleChanged()) { Monitor.Wait(sigLock, timeUntilContinue); } } catch (ThreadInterruptedException) { } } } } catch (Exception re) { if (Log != null) { Log.Error("Runtime error occurred in main trigger firing loop.", re); } } } // while (!halted) // drop references to scheduler stuff to aid garbage collection... qs = null; qsRsrcs = null; }
/// <summary> /// Create a <see cref="QuartzScheduler" /> with the given configuration /// properties. /// </summary> /// <seealso cref="QuartzSchedulerResources" /> public QuartzScheduler(QuartzSchedulerResources resources, SchedulingContext ctxt, TimeSpan idleWaitTime, TimeSpan dbRetryInterval) { Log = LogManager.GetLogger(GetType()); this.resources = resources; try { Bind(); } catch (Exception re) { throw new SchedulerException("Unable to bind scheduler to remoting context.", re); } schedThread = new QuartzSchedulerThread(this, resources, ctxt); if (idleWaitTime > TimeSpan.Zero) { schedThread.IdleWaitTime = idleWaitTime; } if (dbRetryInterval > TimeSpan.Zero) { schedThread.DbFailureRetryInterval = dbRetryInterval; } jobMgr = new ExecutingJobsManager(); AddGlobalJobListener(jobMgr); errLogger = new ErrorLogger(); AddSchedulerListener(errLogger); signaler = new SchedulerSignalerImpl(this, this.schedThread); Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz Scheduler v.{0} created.", Version)); }
protected override IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { SetFactory(qs); return base.Instantiate(rsrcs, qs); }
/// <summary> /// Create a <see cref="QuartzScheduler" /> with the given configuration /// properties. /// </summary> /// <seealso cref="QuartzSchedulerResources" /> public QuartzScheduler(QuartzSchedulerResources resources, TimeSpan idleWaitTime, TimeSpan dbRetryInterval) { log = LogManager.GetLogger(GetType()); this.resources = resources; if (resources.JobStore is IJobListener) { AddInternalJobListener((IJobListener) resources.JobStore); } schedThread = new QuartzSchedulerThread(this, resources); IThreadExecutor schedThreadExecutor = resources.ThreadExecutor; schedThreadExecutor.Execute(schedThread); if (idleWaitTime > TimeSpan.Zero) { schedThread.IdleWaitTime = idleWaitTime; } if (dbRetryInterval > TimeSpan.Zero) { schedThread.DbFailureRetryInterval = dbRetryInterval; } jobMgr = new ExecutingJobsManager(); AddInternalJobListener(jobMgr); errLogger = new ErrorLogger(); AddInternalSchedulerListener(errLogger); signaler = new SchedulerSignalerImpl(this, schedThread); log.InfoFormat(CultureInfo.InvariantCulture, "Quartz Scheduler v.{0} created.", Version); log.Info("Scheduler meta-data: " + (new SchedulerMetaData(SchedulerName, SchedulerInstanceId, GetType(), boundRemotely, RunningSince != null, InStandbyMode, IsShutdown, RunningSince, NumJobsExecuted, JobStoreClass, SupportsPersistence, Clustered, ThreadPoolClass, ThreadPoolSize, Version))); }
protected override IScheduler Instantiate(QuartzSchedulerResources resources, QuartzScheduler scheduler) { scheduler.JobFactory = _jobFactory; return base.Instantiate(resources, scheduler); }
/// <summary> /// Create a <see cref="QuartzScheduler" /> with the given configuration /// properties. /// </summary> /// <seealso cref="QuartzSchedulerResources" /> public QuartzScheduler(QuartzSchedulerResources resources, TimeSpan idleWaitTime) : this() { this.resources = resources; if (resources.JobStore is IJobListener) { AddInternalJobListener((IJobListener) resources.JobStore); } schedThread = new QuartzSchedulerThread(this, resources); schedThread.Start(); if (idleWaitTime > TimeSpan.Zero) { schedThread.IdleWaitTime = idleWaitTime; } jobMgr = new ExecutingJobsManager(); AddInternalJobListener(jobMgr); var errLogger = new ErrorLogger(); AddInternalSchedulerListener(errLogger); SchedulerSignaler = new SchedulerSignalerImpl(this, schedThread); log.InfoFormat("Quartz Scheduler v.{0} created.", Version); }
/// <summary> /// The main processing loop of the <see cref="QuartzSchedulerThread" />. /// </summary> public override void Run() { bool lastAcquireFailed = false; while (!halted) { try { // check if we're supposed to pause... lock (sigLock) { while (paused && !halted) { try { // wait until togglePause(false) is called... Monitor.Wait(sigLock, 1000); } catch (ThreadInterruptedException) { } } if (halted) { break; } } int availTreadCount = qsRsrcs.ThreadPool.BlockForAvailableThreads(); if (availTreadCount > 0) // will always be true, due to semantics of blockForAvailableThreads... { Trigger trigger = null; DateTime now = DateTime.UtcNow; ClearSignaledSchedulingChange(); try { trigger = qsRsrcs.JobStore.AcquireNextTrigger(ctxt, now.Add(idleWaitTime)); lastAcquireFailed = false; } catch (JobPersistenceException jpe) { if (!lastAcquireFailed) { qs.NotifySchedulerListenersError( "An error occured while scanning for the next trigger to fire.", jpe); } lastAcquireFailed = true; } catch (Exception e) { if (!lastAcquireFailed) { Log.Error("quartzSchedulerThreadLoop: RuntimeException " + e.Message, e); } lastAcquireFailed = true; } if (trigger != null) { now = DateTime.UtcNow; DateTime triggerTime = trigger.GetNextFireTimeUtc().Value; TimeSpan timeUntilTrigger = triggerTime - now; while (timeUntilTrigger > TimeSpan.Zero) { lock (sigLock) { try { // we could have blocked a long while // on 'synchronize', so we must recompute now = DateTime.UtcNow; timeUntilTrigger = triggerTime - now; if (timeUntilTrigger.TotalMilliseconds >= 1) { Monitor.Wait(sigLock, timeUntilTrigger); } } catch (ThreadInterruptedException) { } } if (IsScheduleChanged()) { if (IsCandidateNewTimeEarlierWithinReason(triggerTime)) { // above call does a clearSignaledSchedulingChange() try { qsRsrcs.JobStore.ReleaseAcquiredTrigger(ctxt, trigger); } catch (JobPersistenceException jpe) { qs.NotifySchedulerListenersError( "An error occured while releasing trigger '" + trigger.FullName + "'", jpe); // db connection must have failed... keep // retrying until it's up... ReleaseTriggerRetryLoop(trigger); } catch (Exception e) { Log.Error( "releaseTriggerRetryLoop: RuntimeException " + e.Message, e); // db connection must have failed... keep // retrying until it's up... ReleaseTriggerRetryLoop(trigger); } trigger = null; break; } } now = DateTime.UtcNow; timeUntilTrigger = triggerTime - now; } if (trigger == null) { continue; } // set trigger to 'executing' TriggerFiredBundle bndle = null; bool goAhead = true; lock (sigLock) { goAhead = !halted; } if(goAhead) { try { bndle = qsRsrcs.JobStore.TriggerFired(ctxt, trigger); } catch (SchedulerException se) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while firing trigger '{0}'", trigger.FullName), se); } catch (Exception e) { Log.Error( string.Format(CultureInfo.InvariantCulture, "RuntimeException while firing trigger {0}", trigger.FullName), e); // db connection must have failed... keep // retrying until it's up... ReleaseTriggerRetryLoop(trigger); } } // it's possible to get 'null' if the trigger was paused, // blocked, or other similar occurrences that prevent it being // fired at this time... or if the scheduler was shutdown (halted) if (bndle == null) { try { qsRsrcs.JobStore.ReleaseAcquiredTrigger(ctxt, trigger); } catch (SchedulerException se) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while releasing trigger '{0}'", trigger.FullName), se); // db connection must have failed... keep retrying // until it's up... ReleaseTriggerRetryLoop(trigger); } continue; } // TODO: improvements: // // 2- make sure we can get a job runshell before firing trigger, or // don't let that throw an exception (right now it never does, // but the signature says it can). // 3- acquire more triggers at a time (based on num threads available?) JobRunShell shell; try { shell = qsRsrcs.JobRunShellFactory.BorrowJobRunShell(); shell.Initialize(qs, bndle); } catch (SchedulerException) { try { qsRsrcs.JobStore.TriggeredJobComplete(ctxt, trigger, bndle.JobDetail, SchedulerInstruction. SetAllJobTriggersError); } catch (SchedulerException se2) { qs.NotifySchedulerListenersError( string.Format( CultureInfo.InvariantCulture, "An error occured while placing job's triggers in error state '{0}'", trigger.FullName), se2); // db connection must have failed... keep retrying // until it's up... ErrorTriggerRetryLoop(bndle); } continue; } if (qsRsrcs.ThreadPool.RunInThread(shell) == false) { try { // this case should never happen, as it is indicative of the // scheduler being shutdown or a bug in the thread pool or // a thread pool being used concurrently - which the docs // say not to do... Log.Error("ThreadPool.runInThread() return false!"); qsRsrcs.JobStore.TriggeredJobComplete(ctxt, trigger, bndle.JobDetail, SchedulerInstruction. SetAllJobTriggersError); } catch (SchedulerException se2) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while placing job's triggers in error state '{0}'", trigger.FullName), se2); // db connection must have failed... keep retrying // until it's up... ReleaseTriggerRetryLoop(trigger); } } continue; } } else { // if(availTreadCount > 0) continue; // should never happen, if threadPool.blockForAvailableThreads() follows contract } DateTime utcNow = DateTime.UtcNow; DateTime waitTime = utcNow.Add(GetRandomizedIdleWaitTime()); TimeSpan timeUntilContinue = waitTime - utcNow; lock (sigLock) { try { Monitor.Wait(sigLock, timeUntilContinue); } catch (ThreadInterruptedException) { } } } catch (Exception re) { if (Log != null) { Log.Error("Runtime error occured in main trigger firing loop.", re); } } } // loop... // drop references to scheduler stuff to aid garbage collection... qs = null; qsRsrcs = null; }
/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a <see cref="Thread" /> with the given /// attributes. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs, SchedulingContext ctxt, bool setDaemon, int threadPrio) : base(qsRsrcs.ThreadName) { log = LogManager.GetLogger(GetType()); //ThreadGroup generatedAux = qs.SchedulerThreadGroup; this.qs = qs; this.qsRsrcs = qsRsrcs; this.ctxt = ctxt; IsBackground = setDaemon; Priority = (ThreadPriority) threadPrio; // start the underlying thread, but put this object into the 'paused' // state // so processing doesn't start yet... paused = true; halted = false; Start(); }
protected override IScheduler Instantiate(QuartzSchedulerResources resources, QuartzScheduler qs) { IScheduler scheduler = base.Instantiate(resources, qs); scheduler.JobFactory = kernel.Resolve<IJobFactory>(); return scheduler; }
protected override IScheduler Instantiate(QuartzSchedulerResources resources, QuartzScheduler quartzScheduler) { var scheduler = base.Instantiate(resources, quartzScheduler); return scheduler is StdScheduler ? new XpandScheduler(quartzScheduler, _application) : scheduler; }
/// <summary> /// The main processing loop of the <see cref="QuartzSchedulerThread" />. /// </summary> public override void Run() { bool lastAcquireFailed = false; while (!halted) { try { // check if we're supposed to pause... lock (sigLock) { while (paused && !halted) { try { // wait until togglePause(false) is called... Monitor.Wait(sigLock, 1000); } catch (ThreadInterruptedException) { } } if (halted) { break; } } int availTreadCount = qsRsrcs.ThreadPool.BlockForAvailableThreads(); if (availTreadCount > 0) // will always be true, due to semantics of blockForAvailableThreads... { Trigger trigger = null; DateTime now = DateTime.UtcNow; ClearSignaledSchedulingChange(); try { trigger = qsRsrcs.JobStore.AcquireNextTrigger(ctxt, now.Add(idleWaitTime)); lastAcquireFailed = false; } catch (JobPersistenceException jpe) { if (!lastAcquireFailed) { qs.NotifySchedulerListenersError( "An error occured while scanning for the next trigger to fire.", jpe); } lastAcquireFailed = true; } catch (Exception e) { if (!lastAcquireFailed) { Log.Error("quartzSchedulerThreadLoop: RuntimeException " + e.Message, e); } lastAcquireFailed = true; } if (trigger != null) { now = DateTime.UtcNow; DateTime triggerTime = trigger.GetNextFireTimeUtc().Value; TimeSpan timeUntilTrigger = triggerTime - now; while (timeUntilTrigger > TimeSpan.Zero) { lock (sigLock) { try { // we could have blocked a long while // on 'synchronize', so we must recompute now = DateTime.UtcNow; timeUntilTrigger = triggerTime - now; if (timeUntilTrigger.TotalMilliseconds > 1) { Monitor.Wait(sigLock, timeUntilTrigger); } } catch (ThreadInterruptedException) { } } if (IsScheduleChanged()) { if (IsCandidateNewTimeEarlierWithinReason(triggerTime)) { // above call does a clearSignaledSchedulingChange() try { qsRsrcs.JobStore.ReleaseAcquiredTrigger(ctxt, trigger); } catch (JobPersistenceException jpe) { qs.NotifySchedulerListenersError( "An error occured while releasing trigger '" + trigger.FullName + "'", jpe); // db connection must have failed... keep // retrying until it's up... ReleaseTriggerRetryLoop(trigger); } catch (Exception e) { Log.Error( "releaseTriggerRetryLoop: RuntimeException " + e.Message, e); // db connection must have failed... keep // retrying until it's up... ReleaseTriggerRetryLoop(trigger); } trigger = null; break; } } now = DateTime.UtcNow; timeUntilTrigger = triggerTime - now; } if (trigger == null) { continue; } // set trigger to 'executing' TriggerFiredBundle bndle = null; bool goAhead = true; lock (sigLock) { goAhead = !halted; } if (goAhead) { try { bndle = qsRsrcs.JobStore.TriggerFired(ctxt, trigger); } catch (SchedulerException se) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while firing trigger '{0}'", trigger.FullName), se); } catch (Exception e) { Log.Error( string.Format(CultureInfo.InvariantCulture, "RuntimeException while firing trigger {0}", trigger.FullName), e); // db connection must have failed... keep // retrying until it's up... ReleaseTriggerRetryLoop(trigger); } } // it's possible to get 'null' if the trigger was paused, // blocked, or other similar occurrences that prevent it being // fired at this time... or if the scheduler was shutdown (halted) if (bndle == null) { try { qsRsrcs.JobStore.ReleaseAcquiredTrigger(ctxt, trigger); } catch (SchedulerException se) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while releasing trigger '{0}'", trigger.FullName), se); // db connection must have failed... keep retrying // until it's up... ReleaseTriggerRetryLoop(trigger); } continue; } // TODO: improvements: // // 2- make sure we can get a job runshell before firing trigger, or // don't let that throw an exception (right now it never does, // but the signature says it can). // 3- acquire more triggers at a time (based on num threads available?) JobRunShell shell; try { shell = qsRsrcs.JobRunShellFactory.BorrowJobRunShell(); shell.Initialize(qs, bndle); } catch (SchedulerException) { try { qsRsrcs.JobStore.TriggeredJobComplete(ctxt, trigger, bndle.JobDetail, SchedulerInstruction. SetAllJobTriggersError); } catch (SchedulerException se2) { qs.NotifySchedulerListenersError( string.Format( CultureInfo.InvariantCulture, "An error occured while placing job's triggers in error state '{0}'", trigger.FullName), se2); // db connection must have failed... keep retrying // until it's up... ErrorTriggerRetryLoop(bndle); } continue; } if (qsRsrcs.ThreadPool.RunInThread(shell) == false) { try { // this case should never happen, as it is indicative of the // scheduler being shutdown or a bug in the thread pool or // a thread pool being used concurrently - which the docs // say not to do... Log.Error("ThreadPool.runInThread() return false!"); qsRsrcs.JobStore.TriggeredJobComplete(ctxt, trigger, bndle.JobDetail, SchedulerInstruction. SetAllJobTriggersError); } catch (SchedulerException se2) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while placing job's triggers in error state '{0}'", trigger.FullName), se2); // db connection must have failed... keep retrying // until it's up... ReleaseTriggerRetryLoop(trigger); } } continue; } } else { // if(availTreadCount > 0) continue; // should never happen, if threadPool.blockForAvailableThreads() follows contract } DateTime utcNow = DateTime.UtcNow; DateTime waitTime = utcNow.Add(GetRandomizedIdleWaitTime()); TimeSpan timeUntilContinue = waitTime - utcNow; lock (sigLock) { try { Monitor.Wait(sigLock, timeUntilContinue); } catch (ThreadInterruptedException) { } } } catch (Exception re) { if (Log != null) { Log.Error("Runtime error occured in main trigger firing loop.", re); } } } // loop... // drop references to scheduler stuff to aid garbage collection... qs = null; qsRsrcs = null; }
/// <summary> </summary> private IScheduler Instantiate() { if (cfg == null) { Initialize(); } if (initException != null) { throw initException; } ISchedulerExporter exporter = null; IJobStore js; IThreadPool tp; QuartzScheduler qs; SchedulingContext schedCtxt; DBConnectionManager dbMgr = null; string instanceIdGeneratorType = null; NameValueCollection tProps; bool autoId = false; TimeSpan idleWaitTime = TimeSpan.Zero; TimeSpan dbFailureRetry = TimeSpan.Zero; string typeLoadHelperType; string jobFactoryType; SchedulerRepository schedRep = SchedulerRepository.Instance; // Get Scheduler Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string schedName = cfg.GetStringProperty(PropertySchedulerInstanceName, "QuartzScheduler"); string threadName = cfg.GetStringProperty(PropertySchedulerThreadName, string.Format(CultureInfo.InvariantCulture, "{0}_QuartzSchedulerThread", schedName)); string schedInstId = cfg.GetStringProperty(PropertySchedulerInstanceId, DefaultInstanceId); if (schedInstId.Equals(AutoGenerateInstanceId)) { autoId = true; instanceIdGeneratorType = cfg.GetStringProperty(PropertySchedulerInstanceIdGeneratorType, "Quartz.Simpl.SimpleInstanceIdGenerator, Quartz"); } typeLoadHelperType = cfg.GetStringProperty(PropertySchedulerTypeLoadHelperType, "Quartz.Simpl.CascadingClassLoadHelper, Quartz"); jobFactoryType = cfg.GetStringProperty(PropertySchedulerJobFactoryType, null); idleWaitTime = cfg.GetTimeSpanProperty(PropertySchedulerIdleWaitTime, idleWaitTime); dbFailureRetry = cfg.GetTimeSpanProperty(PropertySchedulerDbFailureRetryInterval, dbFailureRetry); bool makeSchedulerThreadDaemon = cfg.GetBooleanProperty(PropertySchedulerMakeSchedulerThreadDaemon); NameValueCollection schedCtxtProps = cfg.GetPropertyGroup(PropertySchedulerContextPrefix, true); bool proxyScheduler = cfg.GetBooleanProperty(PropertySchedulerProxy, false); // If Proxying to remote scheduler, short-circuit here... // ~~~~~~~~~~~~~~~~~~ if (proxyScheduler) { if (autoId) { schedInstId = DefaultInstanceId; } schedCtxt = new SchedulingContext(); schedCtxt.InstanceId = schedInstId; string uid = QuartzSchedulerResources.GetUniqueIdentifier(schedName, schedInstId); RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, uid); string remoteSchedulerAddress = cfg.GetStringProperty(PropertySchedulerProxyAddress); remoteScheduler.RemoteSchedulerAddress = remoteSchedulerAddress; schedRep.Bind(remoteScheduler); return remoteScheduler; } // Create type load helper ITypeLoadHelper loadHelper; try { loadHelper = (ITypeLoadHelper)ObjectUtils.InstantiateType(LoadType(typeLoadHelperType)); } catch (Exception e) { throw new SchedulerConfigException( string.Format(CultureInfo.InvariantCulture, "Unable to instantiate type load helper: {0}", e.Message), e); } loadHelper.Initialize(); IJobFactory jobFactory = null; if (jobFactoryType != null) { try { jobFactory = (IJobFactory) ObjectUtils.InstantiateType(loadHelper.LoadType(jobFactoryType)); } catch (Exception e) { throw new SchedulerConfigException( string.Format(CultureInfo.InvariantCulture, "Unable to Instantiate JobFactory: {0}", e.Message), e); } tProps = cfg.GetPropertyGroup(PropertySchedulerJobFactoryPrefix, true); try { ObjectUtils.SetObjectProperties(jobFactory, tProps); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "JobFactory of type '{0}' props could not be configured.", jobFactoryType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } } IInstanceIdGenerator instanceIdGenerator = null; if (instanceIdGeneratorType != null) { try { instanceIdGenerator = (IInstanceIdGenerator) ObjectUtils.InstantiateType(loadHelper.LoadType(instanceIdGeneratorType)); } catch (Exception e) { throw new SchedulerConfigException( string.Format(CultureInfo.InvariantCulture, "Unable to Instantiate InstanceIdGenerator: {0}", e.Message), e); } tProps = cfg.GetPropertyGroup(PropertySchedulerInstanceIdGeneratorPrefix, true); try { ObjectUtils.SetObjectProperties(instanceIdGenerator, tProps); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "InstanceIdGenerator of type '{0}' props could not be configured.", instanceIdGeneratorType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } } // Get ThreadPool Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string tpType = cfg.GetStringProperty(PropertyThreadPoolType, typeof(SimpleThreadPool).AssemblyQualifiedName); if (tpType == null) { initException = new SchedulerException("ThreadPool type not specified. ", SchedulerException.ErrorBadConfiguration); throw initException; } try { tp = (IThreadPool) ObjectUtils.InstantiateType(loadHelper.LoadType(tpType)); } catch (Exception e) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "ThreadPool type '{0}' could not be instantiated.", tpType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } tProps = cfg.GetPropertyGroup(PropertyThreadPoolPrefix, true); try { ObjectUtils.SetObjectProperties(tp, tProps); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "ThreadPool type '{0}' props could not be configured.", tpType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } // Set up any DataSources // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] dsNames = cfg.GetPropertyGroups(PropertyDataSourcePrefix); for (int i = 0; i < dsNames.Length; i++) { PropertiesParser pp = new PropertiesParser( cfg.GetPropertyGroup(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyDataSourcePrefix, dsNames[i]), true)); string cpType = pp.GetStringProperty(PropertyDbProviderType, null); // custom connectionProvider... if (cpType != null) { IDbProvider cp; try { cp = (IDbProvider) ObjectUtils.InstantiateType(loadHelper.LoadType(cpType)); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "ConnectionProvider of type '{0}' could not be instantiated.", cpType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } try { // remove the type name, so it isn't attempted to be set pp.UnderlyingProperties.Remove(PropertyDbProviderType); ObjectUtils.SetObjectProperties(cp, pp.UnderlyingProperties); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "ConnectionProvider type '{0}' props could not be configured.", cpType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } dbMgr = DBConnectionManager.Instance; dbMgr.AddConnectionProvider(dsNames[i], cp); } else { string dsProvider = pp.GetStringProperty(PropertyDataSourceProvider, null); string dsConnectionString = pp.GetStringProperty(PropertyDataSourceConnectionString, null); string dsConnectionStringName = pp.GetStringProperty(PropertyDataSourceConnectionStringName, null); if (dsConnectionString == null && dsConnectionStringName != null && dsConnectionStringName.Length > 0) { #if NET_20 ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[dsConnectionStringName]; if (connectionStringSettings == null) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Named connection string '{0}' not found for DataSource: {1}", dsConnectionStringName, dsNames[i])); throw initException; } dsConnectionString = connectionStringSettings.ConnectionString; #endif } if (dsProvider == null) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Provider not specified for DataSource: {0}", dsNames[i])); throw initException; } if (dsConnectionString == null) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Connection string not specified for DataSource: {0}", dsNames[i])); throw initException; } try { DbProvider dbp = new DbProvider(dsProvider, dsConnectionString); dbMgr = DBConnectionManager.Instance; dbMgr.AddConnectionProvider(dsNames[i], dbp); } catch (Exception exception) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Could not Initialize DataSource: {0}", dsNames[i]), exception); throw initException; } } } // Get JobStore Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string jsType = cfg.GetStringProperty(PropertyJobStoreType, typeof (RAMJobStore).FullName); if (jsType == null) { initException = new SchedulerException("JobStore type not specified. ", SchedulerException.ErrorBadConfiguration); throw initException; } try { js = (IJobStore) ObjectUtils.InstantiateType(loadHelper.LoadType(jsType)); } catch (Exception e) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "JobStore of type '{0}' could not be instantiated.", jsType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } tProps = cfg.GetPropertyGroup(PropertyJobStorePrefix, true, new string[] {PropertyJobStoreLockHandlerPrefix}); try { ObjectUtils.SetObjectProperties(js, tProps); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "JobStore type '{0}' props could not be configured.", jsType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } if (js is JobStoreSupport) { ((JobStoreSupport) js).InstanceId = schedInstId; ((JobStoreSupport) js).InstanceName = schedName; // Install custom lock handler (Semaphore) string lockHandlerTypeName = cfg.GetStringProperty(PropertyJobStoreLockHandlerType); if (lockHandlerTypeName != null) { try { Type lockHandlerType = loadHelper.LoadType(lockHandlerTypeName); ISemaphore lockHandler; ConstructorInfo cWithDbProvider = lockHandlerType.GetConstructor(new Type[] {typeof (DbProvider)}); if (cWithDbProvider != null) { // takes db provider IDbProvider dbProvider = DBConnectionManager.Instance.GetDbProvider(((JobStoreSupport) js).DataSource); lockHandler = (ISemaphore) cWithDbProvider.Invoke(new object[] { dbProvider }); } else { lockHandler = (ISemaphore)ObjectUtils.InstantiateType(lockHandlerType); } tProps = cfg.GetPropertyGroup(PropertyJobStoreLockHandlerPrefix, true); // If this lock handler requires the table prefix, add it to its properties. if (lockHandler is ITablePrefixAware) { tProps[PropertyTablePrefix] = ((JobStoreSupport) js).TablePrefix; } try { ObjectUtils.SetObjectProperties(lockHandler, tProps); } catch (Exception e) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "JobStore LockHandler type '{0}' props could not be configured.", lockHandlerTypeName), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } ((JobStoreSupport) js).LockHandler = lockHandler; Log.Info("Using custom data access locking (synchronization): " + lockHandlerType); } catch (Exception e) { initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "JobStore LockHandler type '{0}' could not be instantiated.", lockHandlerTypeName), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } } } // Set up any SchedulerPlugins // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] pluginNames = cfg.GetPropertyGroups(PropertyPluginPrefix); ISchedulerPlugin[] plugins = new ISchedulerPlugin[pluginNames.Length]; for (int i = 0; i < pluginNames.Length; i++) { NameValueCollection pp = cfg.GetPropertyGroup(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyPluginPrefix, pluginNames[i]), true); string plugInType = pp[PropertyPluginType] == null ? null : pp[PropertyPluginType]; if (plugInType == null) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "SchedulerPlugin type not specified for plugin '{0}'", pluginNames[i]), SchedulerException.ErrorBadConfiguration); throw initException; } ISchedulerPlugin plugin; try { plugin = (ISchedulerPlugin) ObjectUtils.InstantiateType(LoadType(plugInType)); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "SchedulerPlugin of type '{0}' could not be instantiated.", plugInType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } try { ObjectUtils.SetObjectProperties(plugin, pp); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "JobStore SchedulerPlugin '{0}' props could not be configured.", plugInType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } plugins[i] = plugin; } // Set up any JobListeners // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Type[] strArg = new Type[] {typeof (string)}; string[] jobListenerNames = cfg.GetPropertyGroups(PropertyJobListenerPrefix); IJobListener[] jobListeners = new IJobListener[jobListenerNames.Length]; for (int i = 0; i < jobListenerNames.Length; i++) { NameValueCollection lp = cfg.GetPropertyGroup(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyJobListenerPrefix, jobListenerNames[i]), true); string listenerType = lp[PropertyListenerType] == null ? null : lp[PropertyListenerType]; if (listenerType == null) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "JobListener type not specified for listener '{0}'", jobListenerNames[i]), SchedulerException.ErrorBadConfiguration); throw initException; } IJobListener listener; try { listener = (IJobListener) ObjectUtils.InstantiateType(loadHelper.LoadType(listenerType)); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "JobListener of type '{0}' could not be instantiated.", listenerType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } try { MethodInfo nameSetter = listener.GetType().GetMethod("setName", (strArg == null) ? new Type[0] : strArg); if (nameSetter != null) { nameSetter.Invoke(listener, new object[] {jobListenerNames[i]}); } ObjectUtils.SetObjectProperties(listener, lp); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "JobListener '{0}' props could not be configured.", listenerType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } jobListeners[i] = listener; } // Set up any TriggerListeners // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] triggerListenerNames = cfg.GetPropertyGroups(PropertyTriggerListenerPrefix); ITriggerListener[] triggerListeners = new ITriggerListener[triggerListenerNames.Length]; for (int i = 0; i < triggerListenerNames.Length; i++) { NameValueCollection lp = cfg.GetPropertyGroup( string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyTriggerListenerPrefix, triggerListenerNames[i]), true); string listenerType = lp[PropertyListenerType] == null ? null : lp[PropertyListenerType]; if (listenerType == null) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "TriggerListener type not specified for listener '{0}'", triggerListenerNames[i]), SchedulerException.ErrorBadConfiguration); throw initException; } ITriggerListener listener; try { listener = (ITriggerListener) ObjectUtils.InstantiateType(loadHelper.LoadType(listenerType)); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "TriggerListener of type '{0}' could not be instantiated.", listenerType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } try { MethodInfo nameSetter = listener.GetType().GetMethod("setName", (strArg == null) ? new Type[0] : strArg); if (nameSetter != null) { nameSetter.Invoke(listener, (new object[] {triggerListenerNames[i]})); } ObjectUtils.SetObjectProperties(listener, lp); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "TriggerListener '{0}' props could not be configured.", listenerType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } triggerListeners[i] = listener; } // Get exporter // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string exporterType = cfg.GetStringProperty(PropertySchedulerExporterType, null); if (exporterType != null) { try { exporter = (ISchedulerExporter)ObjectUtils.InstantiateType(loadHelper.LoadType(exporterType)); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "Scheduler exporter of type '{0}' could not be instantiated.", exporterType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } tProps = cfg.GetPropertyGroup(PropertySchedulerExporterPrefix, true); try { ObjectUtils.SetObjectProperties(exporter, tProps); } catch (Exception e) { initException = new SchedulerException( string.Format(CultureInfo.InvariantCulture, "Scheduler exporter type '{0}' props could not be configured.", exporterType), e); initException.ErrorCode = SchedulerException.ErrorBadConfiguration; throw initException; } } // Fire everything up // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IJobRunShellFactory jrsf = new StdJobRunShellFactory(); if (autoId) { try { schedInstId = DefaultInstanceId; if (js is JobStoreSupport) { if (((JobStoreSupport) js).Clustered) { schedInstId = instanceIdGenerator.GenerateInstanceId(); } } } catch (Exception e) { Log.Error("Couldn't generate instance Id!", e); throw new SystemException("Cannot run without an instance id."); } } if (js is JobStoreSupport) { JobStoreSupport jjs = (JobStoreSupport) js; jjs.InstanceId = schedInstId; jjs.DbRetryInterval = dbFailureRetry; } QuartzSchedulerResources rsrcs = new QuartzSchedulerResources(); rsrcs.Name = schedName; rsrcs.ThreadName = threadName; rsrcs.InstanceId = schedInstId; rsrcs.JobRunShellFactory = jrsf; rsrcs.MakeSchedulerThreadDaemon = makeSchedulerThreadDaemon; rsrcs.ThreadPool = tp; rsrcs.SchedulerExporter = exporter; if (tp is SimpleThreadPool) { ((SimpleThreadPool) tp).ThreadNamePrefix = schedName + "_Worker"; } tp.Initialize(); rsrcs.JobStore = js; // add plugins for (int i = 0; i < plugins.Length; i++) { rsrcs.AddSchedulerPlugin(plugins[i]); } schedCtxt = new SchedulingContext(); schedCtxt.InstanceId = rsrcs.InstanceId; qs = new QuartzScheduler(rsrcs, schedCtxt, idleWaitTime, dbFailureRetry); // Create Scheduler ref... IScheduler sched = Instantiate(rsrcs, qs); // set job factory if specified if (jobFactory != null) { qs.JobFactory = jobFactory; } // Initialize plugins now that we have a Scheduler instance. for (int i = 0; i < plugins.Length; i++) { plugins[i].Initialize(pluginNames[i], sched); } // add listeners for (int i = 0; i < jobListeners.Length; i++) { qs.AddGlobalJobListener(jobListeners[i]); } for (int i = 0; i < triggerListeners.Length; i++) { qs.AddGlobalTriggerListener(triggerListeners[i]); } // set scheduler context data... IEnumerator itr = new HashSet(schedCtxtProps).GetEnumerator(); while (itr.MoveNext()) { string key = (String) itr.Current; string val = schedCtxtProps.Get(key); sched.Context.Put(key, val); } // fire up job store, and runshell factory js.Initialize(loadHelper, qs.SchedulerSignaler); jrsf.Initialize(sched, schedCtxt); Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz scheduler '{0}' initialized", sched.SchedulerName)); Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz scheduler version: {0}", qs.Version)); // prevents the repository from being garbage collected qs.AddNoGCObject(schedRep); // prevents the db manager from being garbage collected if (dbMgr != null) { qs.AddNoGCObject(dbMgr); } schedRep.Bind(sched); return sched; }
protected override IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { var scheduler = base.Instantiate(rsrcs, qs); scheduler.JobFactory = _abpJobFactory; return scheduler; }
protected internal virtual IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { SchedulingContext schedCtxt = new SchedulingContext(); schedCtxt.InstanceId = rsrcs.InstanceId; IScheduler sched = new StdScheduler(qs, schedCtxt); return sched; }
protected override IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { qs.JobFactory = this.unityJobFactory; return base.Instantiate(rsrcs, qs); }
/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a non-daemon <see cref="Thread" /> /// with normal priority. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs) : this(qs, qsRsrcs, qsRsrcs.MakeSchedulerThreadDaemon, (int) ThreadPriority.Normal) { }
/// <summary> /// The main processing loop of the <see cref="QuartzSchedulerThread" />. /// </summary> public override void Run() { bool lastAcquireFailed = false; while (!halted) { try { // check if we're supposed to pause... lock (sigLock) { while (paused && !halted) { try { // wait until togglePause(false) is called... Monitor.Wait(sigLock, 1000); } catch (ThreadInterruptedException) { } } if (halted) { break; } } int availThreadCount = qsRsrcs.ThreadPool.BlockForAvailableThreads(); if (availThreadCount > 0) // will always be true, due to semantics of blockForAvailableThreads... { IList <IOperableTrigger> triggers = null; DateTimeOffset now = SystemTime.UtcNow(); ClearSignaledSchedulingChange(); try { triggers = qsRsrcs.JobStore.AcquireNextTriggers( now + idleWaitTime, Math.Min(availThreadCount, qsRsrcs.MaxBatchSize), qsRsrcs.BatchTimeWindow); lastAcquireFailed = false; if (log.IsDebugEnabled) { log.DebugFormat("Batch acquisition of {0} triggers", (triggers == null ? 0 : triggers.Count)); } } catch (JobPersistenceException jpe) { if (!lastAcquireFailed) { qs.NotifySchedulerListenersError("An error occurred while scanning for the next trigger to fire.", jpe); } lastAcquireFailed = true; continue; } catch (Exception e) { if (!lastAcquireFailed) { Log.Error("quartzSchedulerThreadLoop: RuntimeException " + e.Message, e); } lastAcquireFailed = true; continue; } if (triggers != null && triggers.Count > 0) { now = SystemTime.UtcNow(); DateTimeOffset triggerTime = triggers[0].GetNextFireTimeUtc().Value; TimeSpan timeUntilTrigger = triggerTime - now; while (timeUntilTrigger > TimeSpan.FromMilliseconds(2)) { if (ReleaseIfScheduleChangedSignificantly(triggers, triggerTime)) { break; } lock (sigLock) { if (halted) { break; } if (!IsCandidateNewTimeEarlierWithinReason(triggerTime, false)) { try { // we could have blocked a long while // on 'synchronize', so we must recompute now = SystemTime.UtcNow(); timeUntilTrigger = triggerTime - now; if (timeUntilTrigger > TimeSpan.Zero) { Monitor.Wait(sigLock, timeUntilTrigger); } } catch (ThreadInterruptedException) { } } } if (ReleaseIfScheduleChangedSignificantly(triggers, triggerTime)) { break; } now = SystemTime.UtcNow(); timeUntilTrigger = triggerTime - now; } // this happens if releaseIfScheduleChangedSignificantly decided to release triggers if (triggers.Count == 0) { continue; } // set triggers to 'executing' IList <TriggerFiredResult> bndles = new List <TriggerFiredResult>(); bool goAhead = true; lock (sigLock) { goAhead = !halted; } if (goAhead) { try { IList <TriggerFiredResult> res = qsRsrcs.JobStore.TriggersFired(triggers); if (res != null) { bndles = res; } } catch (SchedulerException se) { qs.NotifySchedulerListenersError("An error occurred while firing triggers '" + triggers + "'", se); // QTZ-179 : a problem occurred interacting with the triggers from the db // we release them and loop again foreach (IOperableTrigger t in triggers) { qsRsrcs.JobStore.ReleaseAcquiredTrigger(t); } continue; } } for (int i = 0; i < bndles.Count; i++) { TriggerFiredResult result = bndles[i]; TriggerFiredBundle bndle = result.TriggerFiredBundle; Exception exception = result.Exception; IOperableTrigger trigger = triggers[i]; // TODO SQL exception? if (exception != null && (exception is DbException || exception.InnerException is DbException)) { Log.Error("DbException while firing trigger " + trigger, exception); qsRsrcs.JobStore.ReleaseAcquiredTrigger(trigger); continue; } // it's possible to get 'null' if the triggers was paused, // blocked, or other similar occurrences that prevent it being // fired at this time... or if the scheduler was shutdown (halted) if (bndle == null) { qsRsrcs.JobStore.ReleaseAcquiredTrigger(trigger); continue; } // TODO: improvements: // // 2- make sure we can get a job runshell before firing trigger, or // don't let that throw an exception (right now it never does, // but the signature says it can). // 3- acquire more triggers at a time (based on num threads available?) JobRunShell shell = null; try { shell = qsRsrcs.JobRunShellFactory.CreateJobRunShell(bndle); shell.Initialize(qs); } catch (SchedulerException) { qsRsrcs.JobStore.TriggeredJobComplete(trigger, bndle.JobDetail, SchedulerInstruction.SetAllJobTriggersError); continue; } if (qsRsrcs.ThreadPool.RunInThread(shell) == false) { // this case should never happen, as it is indicative of the // scheduler being shutdown or a bug in the thread pool or // a thread pool being used concurrently - which the docs // say not to do... Log.Error("ThreadPool.runInThread() return false!"); qsRsrcs.JobStore.TriggeredJobComplete(trigger, bndle.JobDetail, SchedulerInstruction.SetAllJobTriggersError); } } continue; // while (!halted) } } else // if(availThreadCount > 0) { // should never happen, if threadPool.blockForAvailableThreads() follows contract continue; // while (!halted) } DateTimeOffset utcNow = SystemTime.UtcNow(); DateTimeOffset waitTime = utcNow.Add(GetRandomizedIdleWaitTime()); TimeSpan timeUntilContinue = waitTime - utcNow; lock (sigLock) { if (!halted) { try { // QTZ-336 A job might have been completed in the mean time and we might have // missed the scheduled changed signal by not waiting for the notify() yet // Check that before waiting for too long in case this very job needs to be // scheduled very soon if (!IsScheduleChanged()) { Monitor.Wait(sigLock, timeUntilContinue); } } catch (ThreadInterruptedException) { } } } } catch (Exception re) { if (Log != null) { Log.Error("Runtime error occurred in main trigger firing loop.", re); } } } // while (!halted) // drop references to scheduler stuff to aid garbage collection... qs = null; qsRsrcs = null; }
/// <summary> /// Construct a new <see cref="QuartzSchedulerThread" /> for the given /// <see cref="QuartzScheduler" /> as a non-daemon <see cref="Thread" /> /// with normal priority. /// </summary> internal QuartzSchedulerThread(QuartzScheduler qs, QuartzSchedulerResources qsRsrcs) : this(qs, qsRsrcs, qsRsrcs.MakeSchedulerThreadDaemon, (int)ThreadPriority.Normal) { }
/// <summary> /// Create a <see cref="QuartzScheduler" /> with the given configuration /// properties. /// </summary> /// <seealso cref="QuartzSchedulerResources" /> public QuartzScheduler(QuartzSchedulerResources resources, TimeSpan idleWaitTime, TimeSpan dbRetryInterval) { this.resources = resources; if (resources.JobStore is IJobListener) { AddInternalJobListener((IJobListener) resources.JobStore); } schedThread = new QuartzSchedulerThread(this, resources); IThreadExecutor schedThreadExecutor = resources.ThreadExecutor; schedThreadExecutor.Execute(schedThread); if (idleWaitTime > TimeSpan.Zero) { schedThread.IdleWaitTime = idleWaitTime; } if (dbRetryInterval > TimeSpan.Zero) { schedThread.DbFailureRetryInterval = dbRetryInterval; } jobMgr = new ExecutingJobsManager(); AddInternalJobListener(jobMgr); errLogger = new ErrorLogger(); AddInternalSchedulerListener(errLogger); signaler = new SchedulerSignalerImpl(this, schedThread); }
/// <summary> /// Create a <see cref="QuartzScheduler" /> with the given configuration /// properties. /// </summary> /// <seealso cref="QuartzSchedulerResources" /> public QuartzScheduler(QuartzSchedulerResources resources, TimeSpan idleWaitTime) { log = LogManager.GetLogger(GetType()); this.resources = resources; if (resources.JobStore is IJobListener) { AddInternalJobListener((IJobListener) resources.JobStore); } schedThread = new QuartzSchedulerThread(this, resources); IThreadExecutor schedThreadExecutor = resources.ThreadExecutor; schedThreadExecutor.Execute(schedThread); if (idleWaitTime > TimeSpan.Zero) { schedThread.IdleWaitTime = idleWaitTime; } jobMgr = new ExecutingJobsManager(); AddInternalJobListener(jobMgr); errLogger = new ErrorLogger(); AddInternalSchedulerListener(errLogger); signaler = new SchedulerSignalerImpl(this, schedThread); log.InfoFormat(CultureInfo.InvariantCulture, "Quartz Scheduler v.{0} created.", Version); }
/// <summary> /// Creates a scheduler using the specified thread pool and job store and /// binds it for remote access. /// </summary> /// <param name="schedulerName">The name for the scheduler.</param> /// <param name="schedulerInstanceId">The instance ID for the scheduler.</param> /// <param name="threadPool">The thread pool for executing jobs</param> /// <param name="threadExecutor">Thread executor.</param> /// <param name="jobStore">The type of job store</param> /// <param name="schedulerPluginMap"></param> /// <param name="idleWaitTime">The idle wait time. You can specify TimeSpan.Zero for /// the default value, which is currently 30000 ms.</param> /// <param name="dbFailureRetryInterval">The db failure retry interval.</param> /// <param name="maxBatchSize">The maximum batch size of triggers, when acquiring them</param> /// <param name="batchTimeWindow">The time window for which it is allowed to "pre-acquire" triggers to fire</param> public virtual void CreateScheduler(string schedulerName, string schedulerInstanceId, IThreadPool threadPool, IThreadExecutor threadExecutor, IJobStore jobStore, IDictionary<string, ISchedulerPlugin> schedulerPluginMap, TimeSpan idleWaitTime, TimeSpan dbFailureRetryInterval, int maxBatchSize, TimeSpan batchTimeWindow) { // Currently only one run-shell factory is available... IJobRunShellFactory jrsf = new StdJobRunShellFactory(); // Fire everything u // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ threadPool.Initialize(); QuartzSchedulerResources qrs = new QuartzSchedulerResources(); qrs.Name = schedulerName; qrs.InstanceId = schedulerInstanceId; SchedulerDetailsSetter.SetDetails(threadPool, schedulerName, schedulerInstanceId); qrs.JobRunShellFactory = jrsf; qrs.ThreadPool = threadPool; qrs.ThreadExecutor= threadExecutor; qrs.JobStore = jobStore; qrs.MaxBatchSize = maxBatchSize; qrs.BatchTimeWindow = batchTimeWindow; // add plugins if (schedulerPluginMap != null) { foreach (ISchedulerPlugin plugin in schedulerPluginMap.Values) { qrs.AddSchedulerPlugin(plugin); } } QuartzScheduler qs = new QuartzScheduler(qrs, idleWaitTime, dbFailureRetryInterval); ITypeLoadHelper cch = new SimpleTypeLoadHelper(); cch.Initialize(); SchedulerDetailsSetter.SetDetails(jobStore, schedulerName, schedulerInstanceId); jobStore.Initialize(cch, qs.SchedulerSignaler); IScheduler scheduler = new StdScheduler(qs); jrsf.Initialize(scheduler); qs.Initialize(); // Initialize plugins now that we have a Scheduler instance. if (schedulerPluginMap != null) { foreach (var pluginEntry in schedulerPluginMap) { pluginEntry.Value.Initialize(pluginEntry.Key, scheduler); } } Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz scheduler '{0}", scheduler.SchedulerName)); Log.Info(string.Format(CultureInfo.InvariantCulture, "Quartz scheduler version: {0}", qs.Version)); SchedulerRepository schedRep = SchedulerRepository.Instance; qs.AddNoGCObject(schedRep); // prevents the repository from being // garbage collected schedRep.Bind(scheduler); initialized = true; }
/// <summary> </summary> private IScheduler Instantiate() { if (cfg == null) { Initialize(); } if (initException != null) { throw initException; } ISchedulerExporter exporter = null; IJobStore js; IThreadPool tp; QuartzScheduler qs = null; DBConnectionManager dbMgr = null; Type instanceIdGeneratorType = null; NameValueCollection tProps; bool autoId = false; TimeSpan idleWaitTime = TimeSpan.Zero; TimeSpan dbFailureRetry = TimeSpan.FromSeconds(15); IThreadExecutor threadExecutor; SchedulerRepository schedRep = SchedulerRepository.Instance; // Get Scheduler Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string schedName = cfg.GetStringProperty(PropertySchedulerInstanceName, "QuartzScheduler"); string threadName = cfg.GetStringProperty(PropertySchedulerThreadName, "{0}_QuartzSchedulerThread".FormatInvariant(schedName)); string schedInstId = cfg.GetStringProperty(PropertySchedulerInstanceId, DefaultInstanceId); if (schedInstId.Equals(AutoGenerateInstanceId)) { autoId = true; instanceIdGeneratorType = LoadType(cfg.GetStringProperty(PropertySchedulerInstanceIdGeneratorType)) ?? typeof(SimpleInstanceIdGenerator); } else if (schedInstId.Equals(SystemPropertyAsInstanceId)) { autoId = true; instanceIdGeneratorType = typeof(SystemPropertyInstanceIdGenerator); } Type typeLoadHelperType = LoadType(cfg.GetStringProperty(PropertySchedulerTypeLoadHelperType)); Type jobFactoryType = LoadType(cfg.GetStringProperty(PropertySchedulerJobFactoryType, null)); idleWaitTime = cfg.GetTimeSpanProperty(PropertySchedulerIdleWaitTime, idleWaitTime); if (idleWaitTime > TimeSpan.Zero && idleWaitTime < TimeSpan.FromMilliseconds(1000)) { throw new SchedulerException("quartz.scheduler.idleWaitTime of less than 1000ms is not legal."); } dbFailureRetry = cfg.GetTimeSpanProperty(PropertySchedulerDbFailureRetryInterval, dbFailureRetry); if (dbFailureRetry < TimeSpan.Zero) { throw new SchedulerException(PropertySchedulerDbFailureRetryInterval + " of less than 0 ms is not legal."); } bool makeSchedulerThreadDaemon = cfg.GetBooleanProperty(PropertySchedulerMakeSchedulerThreadDaemon); long batchTimeWindow = cfg.GetLongProperty(PropertySchedulerBatchTimeWindow, 0L); int maxBatchSize = cfg.GetIntProperty(PropertySchedulerMaxBatchSize, 1); bool interruptJobsOnShutdown = cfg.GetBooleanProperty(PropertySchedulerInterruptJobsOnShutdown, false); bool interruptJobsOnShutdownWithWait = cfg.GetBooleanProperty(PropertySchedulerInterruptJobsOnShutdownWithWait, false); NameValueCollection schedCtxtProps = cfg.GetPropertyGroup(PropertySchedulerContextPrefix, true); bool proxyScheduler = cfg.GetBooleanProperty(PropertySchedulerProxy, false); // Create type load helper ITypeLoadHelper loadHelper; try { loadHelper = ObjectUtils.InstantiateType<ITypeLoadHelper>(typeLoadHelperType ?? typeof(SimpleTypeLoadHelper)); } catch (Exception e) { throw new SchedulerConfigException("Unable to instantiate type load helper: {0}".FormatInvariant(e.Message), e); } loadHelper.Initialize(); // If Proxying to remote scheduler, short-circuit here... // ~~~~~~~~~~~~~~~~~~ if (proxyScheduler) { if (autoId) { schedInstId = DefaultInstanceId; } Type proxyType = loadHelper.LoadType(cfg.GetStringProperty(PropertySchedulerProxyType)) ?? typeof(RemotingSchedulerProxyFactory); IRemotableSchedulerProxyFactory factory; try { factory = ObjectUtils.InstantiateType<IRemotableSchedulerProxyFactory>(proxyType); ObjectUtils.SetObjectProperties(factory, cfg.GetPropertyGroup(PropertySchedulerProxy, true)); } catch (Exception e) { initException = new SchedulerException("Remotable proxy factory '{0}' could not be instantiated.".FormatInvariant(proxyType), e); throw initException; } string uid = QuartzSchedulerResources.GetUniqueIdentifier(schedName, schedInstId); RemoteScheduler remoteScheduler = new RemoteScheduler(uid, factory); schedRep.Bind(remoteScheduler); return remoteScheduler; } IJobFactory jobFactory = null; if (jobFactoryType != null) { try { jobFactory = ObjectUtils.InstantiateType<IJobFactory>(jobFactoryType); } catch (Exception e) { throw new SchedulerConfigException("Unable to Instantiate JobFactory: {0}".FormatInvariant(e.Message), e); } tProps = cfg.GetPropertyGroup(PropertySchedulerJobFactoryPrefix, true); try { ObjectUtils.SetObjectProperties(jobFactory, tProps); } catch (Exception e) { initException = new SchedulerException("JobFactory of type '{0}' props could not be configured.".FormatInvariant(jobFactoryType), e); throw initException; } } IInstanceIdGenerator instanceIdGenerator = null; if (instanceIdGeneratorType != null) { try { instanceIdGenerator = ObjectUtils.InstantiateType<IInstanceIdGenerator>(instanceIdGeneratorType); } catch (Exception e) { throw new SchedulerConfigException("Unable to Instantiate InstanceIdGenerator: {0}".FormatInvariant(e.Message), e); } tProps = cfg.GetPropertyGroup(PropertySchedulerInstanceIdGeneratorPrefix, true); try { ObjectUtils.SetObjectProperties(instanceIdGenerator, tProps); } catch (Exception e) { initException = new SchedulerException("InstanceIdGenerator of type '{0}' props could not be configured.".FormatInvariant(instanceIdGeneratorType), e); throw initException; } } // Get ThreadPool Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Type tpType = loadHelper.LoadType(cfg.GetStringProperty(PropertyThreadPoolType)) ?? typeof(SimpleThreadPool); try { tp = ObjectUtils.InstantiateType<IThreadPool>(tpType); } catch (Exception e) { initException = new SchedulerException("ThreadPool type '{0}' could not be instantiated.".FormatInvariant(tpType), e); throw initException; } tProps = cfg.GetPropertyGroup(PropertyThreadPoolPrefix, true); try { ObjectUtils.SetObjectProperties(tp, tProps); } catch (Exception e) { initException = new SchedulerException("ThreadPool type '{0}' props could not be configured.".FormatInvariant(tpType), e); throw initException; } // Set up any DataSources // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] dsNames = cfg.GetPropertyGroups(PropertyDataSourcePrefix); for (int i = 0; i < dsNames.Length; i++) { string datasourceKey = "{0}.{1}".FormatInvariant( PropertyDataSourcePrefix, dsNames[i]); NameValueCollection propertyGroup = cfg.GetPropertyGroup(datasourceKey, true); PropertiesParser pp = new PropertiesParser(propertyGroup); Type cpType = loadHelper.LoadType(pp.GetStringProperty(PropertyDbProviderType, null)); // custom connectionProvider... if (cpType != null) { IDbProvider cp; try { cp = ObjectUtils.InstantiateType<IDbProvider>(cpType); } catch (Exception e) { initException = new SchedulerException("ConnectionProvider of type '{0}' could not be instantiated.".FormatInvariant(cpType), e); throw initException; } try { // remove the type name, so it isn't attempted to be set pp.UnderlyingProperties.Remove(PropertyDbProviderType); ObjectUtils.SetObjectProperties(cp, pp.UnderlyingProperties); cp.Initialize(); } catch (Exception e) { initException = new SchedulerException("ConnectionProvider type '{0}' props could not be configured.".FormatInvariant(cpType), e); throw initException; } dbMgr = DBConnectionManager.Instance; dbMgr.AddConnectionProvider(dsNames[i], cp); } else { string dsProvider = pp.GetStringProperty(PropertyDataSourceProvider, null); string dsConnectionString = pp.GetStringProperty(PropertyDataSourceConnectionString, null); string dsConnectionStringName = pp.GetStringProperty(PropertyDataSourceConnectionStringName, null); if (dsConnectionString == null && !String.IsNullOrEmpty(dsConnectionStringName)) { ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[dsConnectionStringName]; if (connectionStringSettings == null) { initException = new SchedulerException("Named connection string '{0}' not found for DataSource: {1}".FormatInvariant(dsConnectionStringName, dsNames[i])); throw initException; } dsConnectionString = connectionStringSettings.ConnectionString; } if (dsProvider == null) { initException = new SchedulerException("Provider not specified for DataSource: {0}".FormatInvariant(dsNames[i])); throw initException; } if (dsConnectionString == null) { initException = new SchedulerException("Connection string not specified for DataSource: {0}".FormatInvariant(dsNames[i])); throw initException; } try { DbProvider dbp = new DbProvider(dsProvider, dsConnectionString); dbp.Initialize(); dbMgr = DBConnectionManager.Instance; dbMgr.AddConnectionProvider(dsNames[i], dbp); } catch (Exception exception) { initException = new SchedulerException("Could not Initialize DataSource: {0}".FormatInvariant(dsNames[i]), exception); throw initException; } } } // Get object serializer properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IObjectSerializer objectSerializer; string objectSerializerType = cfg.GetStringProperty("quartz.serializer.type"); if (objectSerializerType != null) { tProps = cfg.GetPropertyGroup(PropertyObjectSerializer, true); try { objectSerializer = ObjectUtils.InstantiateType<IObjectSerializer>(loadHelper.LoadType(objectSerializerType)); log.Info("Using custom implementation for object serializer: " + objectSerializerType); ObjectUtils.SetObjectProperties(objectSerializer, tProps); } catch (Exception e) { initException = new SchedulerException("Object serializer type '" + objectSerializerType + "' could not be instantiated.", e); throw initException; } } else { log.Info("Using default implementation for object serializer"); objectSerializer = new DefaultObjectSerializer(); } // Get JobStore Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Type jsType = loadHelper.LoadType(cfg.GetStringProperty(PropertyJobStoreType)); try { js = ObjectUtils.InstantiateType<IJobStore>(jsType ?? typeof(RAMJobStore)); } catch (Exception e) { initException = new SchedulerException("JobStore of type '{0}' could not be instantiated.".FormatInvariant(jsType), e); throw initException; } SchedulerDetailsSetter.SetDetails(js, schedName, schedInstId); tProps = cfg.GetPropertyGroup(PropertyJobStorePrefix, true, new string[] {PropertyJobStoreLockHandlerPrefix}); try { ObjectUtils.SetObjectProperties(js, tProps); } catch (Exception e) { initException = new SchedulerException("JobStore type '{0}' props could not be configured.".FormatInvariant(jsType), e); throw initException; } if (js is JobStoreSupport) { // Install custom lock handler (Semaphore) Type lockHandlerType = loadHelper.LoadType(cfg.GetStringProperty(PropertyJobStoreLockHandlerType)); if (lockHandlerType != null) { try { ISemaphore lockHandler; ConstructorInfo cWithDbProvider = lockHandlerType.GetConstructor(new Type[] {typeof (DbProvider)}); if (cWithDbProvider != null) { // takes db provider IDbProvider dbProvider = DBConnectionManager.Instance.GetDbProvider(((JobStoreSupport) js).DataSource); lockHandler = (ISemaphore) cWithDbProvider.Invoke(new object[] { dbProvider }); } else { lockHandler = ObjectUtils.InstantiateType<ISemaphore>(lockHandlerType); } tProps = cfg.GetPropertyGroup(PropertyJobStoreLockHandlerPrefix, true); // If this lock handler requires the table prefix, add it to its properties. if (lockHandler is ITablePrefixAware) { tProps[PropertyTablePrefix] = ((JobStoreSupport) js).TablePrefix; tProps[PropertySchedulerName] = schedName; } try { ObjectUtils.SetObjectProperties(lockHandler, tProps); } catch (Exception e) { initException = new SchedulerException("JobStore LockHandler type '{0}' props could not be configured.".FormatInvariant(lockHandlerType), e); throw initException; } ((JobStoreSupport) js).LockHandler = lockHandler; Log.Info("Using custom data access locking (synchronization): " + lockHandlerType); } catch (Exception e) { initException = new SchedulerException("JobStore LockHandler type '{0}' could not be instantiated.".FormatInvariant(lockHandlerType), e); throw initException; } } } // Set up any SchedulerPlugins // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] pluginNames = cfg.GetPropertyGroups(PropertyPluginPrefix); ISchedulerPlugin[] plugins = new ISchedulerPlugin[pluginNames.Length]; for (int i = 0; i < pluginNames.Length; i++) { NameValueCollection pp = cfg.GetPropertyGroup("{0}.{1}".FormatInvariant(PropertyPluginPrefix, pluginNames[i]), true); string plugInType = pp[PropertyPluginType] ?? null; if (plugInType == null) { initException = new SchedulerException("SchedulerPlugin type not specified for plugin '{0}'".FormatInvariant(pluginNames[i])); throw initException; } ISchedulerPlugin plugin; try { plugin = ObjectUtils.InstantiateType<ISchedulerPlugin>(LoadType(plugInType)); } catch (Exception e) { initException = new SchedulerException("SchedulerPlugin of type '{0}' could not be instantiated.".FormatInvariant(plugInType), e); throw initException; } try { ObjectUtils.SetObjectProperties(plugin, pp); } catch (Exception e) { initException = new SchedulerException("JobStore SchedulerPlugin '{0}' props could not be configured.".FormatInvariant(plugInType), e); throw initException; } plugins[i] = plugin; } // Set up any JobListeners // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] jobListenerNames = cfg.GetPropertyGroups(PropertyJobListenerPrefix); IJobListener[] jobListeners = new IJobListener[jobListenerNames.Length]; for (int i = 0; i < jobListenerNames.Length; i++) { NameValueCollection lp = cfg.GetPropertyGroup("{0}.{1}".FormatInvariant(PropertyJobListenerPrefix, jobListenerNames[i]), true); string listenerType = lp[PropertyListenerType]; if (listenerType == null) { initException = new SchedulerException("JobListener type not specified for listener '{0}'".FormatInvariant(jobListenerNames[i])); throw initException; } IJobListener listener; try { listener = ObjectUtils.InstantiateType<IJobListener>(loadHelper.LoadType(listenerType)); } catch (Exception e) { initException = new SchedulerException("JobListener of type '{0}' could not be instantiated.".FormatInvariant(listenerType), e); throw initException; } try { PropertyInfo nameProperty = listener.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); if (nameProperty != null && nameProperty.CanWrite) { nameProperty.GetSetMethod().Invoke(listener, new object[] {jobListenerNames[i]}); } ObjectUtils.SetObjectProperties(listener, lp); } catch (Exception e) { initException = new SchedulerException("JobListener '{0}' props could not be configured.".FormatInvariant(listenerType), e); throw initException; } jobListeners[i] = listener; } // Set up any TriggerListeners // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string[] triggerListenerNames = cfg.GetPropertyGroups(PropertyTriggerListenerPrefix); ITriggerListener[] triggerListeners = new ITriggerListener[triggerListenerNames.Length]; for (int i = 0; i < triggerListenerNames.Length; i++) { NameValueCollection lp = cfg.GetPropertyGroup("{0}.{1}".FormatInvariant(PropertyTriggerListenerPrefix, triggerListenerNames[i]), true); string listenerType = lp[PropertyListenerType]; if (listenerType == null) { initException = new SchedulerException("TriggerListener type not specified for listener '{0}'".FormatInvariant(triggerListenerNames[i])); throw initException; } ITriggerListener listener; try { listener = ObjectUtils.InstantiateType<ITriggerListener>(loadHelper.LoadType(listenerType)); } catch (Exception e) { initException = new SchedulerException("TriggerListener of type '{0}' could not be instantiated.".FormatInvariant(listenerType), e); throw initException; } try { PropertyInfo nameProperty = listener.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); if (nameProperty != null && nameProperty.CanWrite) { nameProperty.GetSetMethod().Invoke(listener, new object[] {triggerListenerNames[i]}); } ObjectUtils.SetObjectProperties(listener, lp); } catch (Exception e) { initException = new SchedulerException("TriggerListener '{0}' props could not be configured.".FormatInvariant(listenerType), e); throw initException; } triggerListeners[i] = listener; } // Get exporter // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string exporterType = cfg.GetStringProperty(PropertySchedulerExporterType, null); if (exporterType != null) { try { exporter = ObjectUtils.InstantiateType<ISchedulerExporter>(loadHelper.LoadType(exporterType)); } catch (Exception e) { initException = new SchedulerException("Scheduler exporter of type '{0}' could not be instantiated.".FormatInvariant(exporterType), e); throw initException; } tProps = cfg.GetPropertyGroup(PropertySchedulerExporterPrefix, true); try { ObjectUtils.SetObjectProperties(exporter, tProps); } catch (Exception e) { initException = new SchedulerException("Scheduler exporter type '{0}' props could not be configured.".FormatInvariant(exporterType), e); throw initException; } } bool tpInited = false; bool qsInited = false; // Get ThreadExecutor Properties // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ string threadExecutorClass = cfg.GetStringProperty(PropertyThreadExecutorType); if (threadExecutorClass != null) { tProps = cfg.GetPropertyGroup(PropertyThreadExecutor, true); try { threadExecutor = ObjectUtils.InstantiateType<IThreadExecutor>(loadHelper.LoadType(threadExecutorClass)); log.Info("Using custom implementation for ThreadExecutor: " + threadExecutorClass); ObjectUtils.SetObjectProperties(threadExecutor, tProps); } catch (Exception e) { initException = new SchedulerException( "ThreadExecutor class '" + threadExecutorClass + "' could not be instantiated.", e); throw initException; } } else { log.Info("Using default implementation for ThreadExecutor"); threadExecutor = new DefaultThreadExecutor(); } // Fire everything up // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ try { IJobRunShellFactory jrsf = new StdJobRunShellFactory(); if (autoId) { try { schedInstId = DefaultInstanceId; if (js.Clustered) { schedInstId = instanceIdGenerator.GenerateInstanceId(); } } catch (Exception e) { Log.Error("Couldn't generate instance Id!", e); throw new SystemException("Cannot run without an instance id."); } } if (js is JobStoreSupport) { JobStoreSupport jjs = (JobStoreSupport) js; jjs.DbRetryInterval = dbFailureRetry; jjs.ThreadExecutor = threadExecutor; // object serializer jjs.ObjectSerializer = objectSerializer; } QuartzSchedulerResources rsrcs = new QuartzSchedulerResources(); rsrcs.Name = schedName; rsrcs.ThreadName = threadName; rsrcs.InstanceId = schedInstId; rsrcs.JobRunShellFactory = jrsf; rsrcs.MakeSchedulerThreadDaemon = makeSchedulerThreadDaemon; rsrcs.BatchTimeWindow = TimeSpan.FromMilliseconds(batchTimeWindow); rsrcs.MaxBatchSize = maxBatchSize; rsrcs.InterruptJobsOnShutdown = interruptJobsOnShutdown; rsrcs.InterruptJobsOnShutdownWithWait = interruptJobsOnShutdownWithWait; rsrcs.SchedulerExporter = exporter; SchedulerDetailsSetter.SetDetails(tp, schedName, schedInstId); rsrcs.ThreadExecutor = threadExecutor; threadExecutor.Initialize(); rsrcs.ThreadPool = tp; if (tp is SimpleThreadPool) { ((SimpleThreadPool) tp).ThreadNamePrefix = schedName + "_Worker"; } tp.Initialize(); tpInited = true; rsrcs.JobStore = js; // add plugins for (int i = 0; i < plugins.Length; i++) { rsrcs.AddSchedulerPlugin(plugins[i]); } qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry); qsInited = true; // Create Scheduler ref... IScheduler sched = Instantiate(rsrcs, qs); // set job factory if specified if (jobFactory != null) { qs.JobFactory = jobFactory; } // Initialize plugins now that we have a Scheduler instance. for (int i = 0; i < plugins.Length; i++) { plugins[i].Initialize(pluginNames[i], sched); } // add listeners for (int i = 0; i < jobListeners.Length; i++) { qs.ListenerManager.AddJobListener(jobListeners[i], EverythingMatcher<JobKey>.AllJobs()); } for (int i = 0; i < triggerListeners.Length; i++) { qs.ListenerManager.AddTriggerListener(triggerListeners[i], EverythingMatcher<TriggerKey>.AllTriggers()); } // set scheduler context data... foreach (string key in schedCtxtProps) { string val = schedCtxtProps.Get(key); sched.Context.Put(key, val); } // fire up job store, and runshell factory js.InstanceId = schedInstId; js.InstanceName = schedName; js.ThreadPoolSize = tp.PoolSize; js.Initialize(loadHelper, qs.SchedulerSignaler); jrsf.Initialize(sched); qs.Initialize(); Log.Info("Quartz scheduler '{0}' initialized".FormatInvariant(sched.SchedulerName)); Log.Info("Quartz scheduler version: {0}".FormatInvariant(qs.Version)); // prevents the repository from being garbage collected qs.AddNoGCObject(schedRep); // prevents the db manager from being garbage collected if (dbMgr != null) { qs.AddNoGCObject(dbMgr); } schedRep.Bind(sched); return sched; } catch (SchedulerException) { if (qsInited) { qs.Shutdown(false); } else if (tpInited) { tp.Shutdown(false); } throw; } catch { if (qsInited) { qs.Shutdown(false); } else if (tpInited) { tp.Shutdown(false); } throw; } }
protected virtual IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { IScheduler sched = new StdScheduler(qs); return sched; }
protected override IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { SetFactory(qs); var res = new CustomScheduler(qs, _container); AddListeners(res); return res; }