public override void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { Log.TraceFormat("Trigger complete for job {0} with scheduler instruction {1}", context.JobDetail.JobType, triggerInstructionCode ); }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { // Note that we do not have access to job exception in TriggerComplete if (!_handleJobInsteadOfTriggerForCompletion) { // According to Quartz.NET recomendations we should make sure // listeners never throw any exceptions because that could // cause issues at a global Scheduler scope. try { OnEventEmitted(new RawSchedulerEvent( SchedulerEventScope.Trigger, SchedulerEventType.Complete, context.Trigger.Key.ToString(), context.FireInstanceId, null, context.Result)); } catch { // just ignore this } } }
/// <summary> /// Job完成时调用 /// </summary> /// <param name="trigger">触发器</param> /// <param name="context">上下文</param> /// <param name="triggerInstructionCode"></param> public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { if (context.NextFireTimeUtc.HasValue) { TaskHelper.UpdateLastRunTime(trigger.JobKey.Name, TimeZoneInfo.ConvertTimeFromUtc(context.NextFireTimeUtc.Value.DateTime, TimeZoneInfo.Local)); } }
/// <summary> /// Trigger 被触发并且完成了 Job 的执行时,Scheduler 调用这个方法。这不是说这个 Trigger 将不再触发了,而仅仅是当前 Trigger 的触发(并且紧接着的 Job 执行) 结束时。这个 Trigger /// 也许还要在将来触发多次的。 /// Called by the Quartz.IScheduler when a Quartz.ITrigger has fired, it's associated /// Quartz.IJobDetail has been executed, and it's Quartz.Spi.IOperableTrigger.Triggered(Quartz.ICalendar) /// method has been called. /// </summary> /// <param name="trigger">The Quartz.ITrigger that was fired.</param> /// <param name="context"> /// The Quartz.IJobExecutionContext that was passed to the /// Quartz.IJob'sQuartz.IJob.Execute(Quartz.IJobExecutionContext) method. /// </param> /// <param name="triggerInstructionCode"> /// The result of the call on the /// Quartz.ITrigger'sQuartz.Spi.IOperableTrigger.Triggered(Quartz.ICalendar) method. /// </param> /// <param name="cancellationToken">The cancellation instruction.</param> /// <returns></returns> public virtual async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { Debug(nameof(ITriggerListener), nameof(TriggerComplete)); var beginTicks = context.GetJobBeginDateTimeTicks(); var milliseconds = (long)TimeSpan.FromTicks(DateTime.Now.Ticks - beginTicks).TotalMilliseconds; if (milliseconds > 5 * 1000) { JobLogHelper.Warn($"{JobInfo} 耗时{milliseconds} ms ", null, nameof(TriggerComplete)); } else if (milliseconds > 0) { JobLogHelper.Info($"{JobInfo} 耗时{milliseconds} ms ", nameof(TriggerComplete)); } var bizState = context.GetJobBusinessState(); var bizStatsStr = bizState.ToString(); if (bizState == JobBusinessStateEnum.Success) { bizStatsStr = $"<font color=#20CE43>{bizState}</font>"; } if (bizState == JobBusinessStateEnum.Fail) { bizStatsStr = $"<font color=#FF0000>{bizState}</font>"; } await DoNoticeAsync($"耗时 {milliseconds} ms. 任务状态为 {bizStatsStr}", context.GetTempConfig("BizContent").ToString()); await Task.CompletedTask; }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { foreach (ITriggerListener l in listeners) { l.TriggerComplete(trigger, context, triggerInstructionCode); } }
/// <summary> /// Trigger完成 /// </summary> /// <param name="trigger"></param> /// <param name="context"></param> /// <param name="triggerInstructionCode"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { var jobId = trigger.JobKey.Name; //_logger.Debug($"{jobId}完成"); return(Task.CompletedTask); }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { var jobKey = context.JobDetail.Key; //Logger.Instance.InfoFormat($"{jobKey.Name}--{jobKey.Group} completed,{context.NextFireTimeUtc.Value.DateTime}"); JobOperator.UpdateNextFireTimeAsync(jobKey.Name, jobKey.Group, TimeZoneInfo.ConvertTimeFromUtc(context.NextFireTimeUtc.Value.DateTime, TimeZoneInfo.Local)).Wait(); }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken) { return(Task.FromResult(true)); }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken) { return(TaskUtil.CompletedTask); }
/// <summary> /// Called by the <see cref="IScheduler" /> when a <see cref="ITrigger" /> /// has fired, it's associated <see cref="IJobDetail" /> /// has been executed, and it's <see cref="IOperableTrigger.Triggered" /> method has been /// called. /// </summary> /// <param name="trigger"></param> /// <param name="context"></param> /// <param name="triggerInstructionCode"></param> public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { Logger.InfoFormat("TriggerComplete: {0}, {1}", trigger.Key.Name, trigger.Key.Group); var auditLog = GetAuditLog(trigger, "TriggerComplete", context); _persistanceStore.InsertAuditLog(auditLog); }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken)) { return(Task.Run(() => { AddToListBox(context); } )); }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken)) { ILoggerFactory loggerFact = Program.Host.Services.GetService <ILoggerFactory>(); var _logger = loggerFact.CreateLogger <ZookeeperService>(); _logger.LogInformation(0, null, "执行成功.name:{0} group:{1}", context.JobDetail.Key.Name, context.JobDetail.Key.Group); return(Task.FromResult(true)); }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { OnEventEmitted(new SchedulerEvent( SchedulerEventScope.Trigger, SchedulerEventType.Complete, context.Trigger.Key.ToString(), context.FireInstanceId)); }
public Task TriggerComplete( ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { return(IterateListenersInGuard(l => l.TriggerComplete(trigger, context, triggerInstructionCode, cancellationToken), nameof(TriggerComplete))); }
public Task TriggerComplete( ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { return(Task.WhenAll(listeners.Select(l => l.TriggerComplete(trigger, context, triggerInstructionCode, cancellationToken)))); }
public virtual Task TriggerComplete( ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { return(Task.CompletedTask); }
public void TriggeredJobComplete(Trigger trigger, IScheduledJob job, SchedulerInstruction triggerInstCode) { lock (_triggerLock) { JobWrapper jw = _jobsDictionary[job.Name] as JobWrapper; TriggerWrapper tw = _triggersDictionary[trigger.Name] as TriggerWrapper; // even if it was deleted, there may be cleanup to do _blockedJobs.Remove(job.Name); // check for trigger deleted during execution... if (tw != null) { if (triggerInstCode == SchedulerInstruction.DeleteTrigger) { //log.Debug("Deleting trigger"); NullableDateTime d = trigger.GetNextFireTimeUtc(); if (!d.HasValue) { // double check for possible reschedule within job // execution, which would cancel the need to delete... d = tw.Trigger.GetNextFireTimeUtc(); if (!d.HasValue) { RemoveTrigger(trigger.Name); } else { log.Debug("Deleting cancelled - trigger still active"); } } else { RemoveTrigger(trigger.Name); } } else if (triggerInstCode == SchedulerInstruction.SetTriggerComplete) { tw.State = InternalTriggerState.Complete; _timeTriggers.Remove(tw); } else if (triggerInstCode == SchedulerInstruction.SetTriggerError) { log.Info(string.Format(CultureInfo.InvariantCulture, "Trigger {0} set to ERROR state.", trigger.Name)); tw.State = InternalTriggerState.Error; } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersError) { log.Info(string.Format(CultureInfo.InvariantCulture, "All triggers of Job {0} set to ERROR state.", trigger.Name)); SetAllTriggersOfJobToState(trigger.Name, InternalTriggerState.Error); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersComplete) { SetAllTriggersOfJobToState(trigger.Name, InternalTriggerState.Complete); } } } }
private Task <bool> NotifyTriggerListenersComplete( IJobExecutionContext ctx, SchedulerInstruction instCode, CancellationToken cancellationToken = default) { var nextFireTimeUtc = ctx.Trigger.GetNextFireTimeUtc(); // check if we can do quick path if (nextFireTimeUtc != null) { try { var task = qs !.NotifyTriggerListenersComplete(ctx, instCode, cancellationToken); return(task.IsCompletedSuccessfully() ? Task.FromResult(true) : DoNotify(task)); } catch (SchedulerException se) { return(NotifyError(se)); } } return(NotifyAwaited()); async Task <bool> NotifyAwaited() { await DoNotify(qs !.NotifyTriggerListenersComplete(ctx, instCode, cancellationToken)).ConfigureAwait(false); if (!nextFireTimeUtc.HasValue) { await qs.NotifySchedulerListenersFinalized(ctx.Trigger, cancellationToken).ConfigureAwait(false); } return(true); } async Task <bool> DoNotify(Task t) { try { await t.ConfigureAwait(false); return(true); } catch (SchedulerException se) { return(await NotifyError(se).ConfigureAwait(false)); } } async Task <bool> NotifyError(SchedulerException se) { string msg = $"Unable to notify TriggerListener(s) of Job that was executed: (error will be ignored). trigger= {ctx.Trigger.Key} job= {ctx.JobDetail.Key}"; await qs !.NotifySchedulerListenersError(msg, se, cancellationToken).ConfigureAwait(false); return(false); } }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { var jobKey = context.JobDetail.Key; var jobTrigger = trigger.Key; Task task = Task.Run(() => Console.WriteLine("{0} Completed for {1}", jobTrigger, jobKey)); return(task); }
/// <summary> /// Job完成时调用 /// </summary> /// <param name="trigger"></param> /// <param name="context"></param> /// <param name="triggerInstructionCode"></param> public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { Guid guid; if (Guid.TryParse(trigger.JobKey.Name, out guid)) { new TaskService().UpdateNextFireTime(trigger.JobKey.Name, TimeZoneInfo.ConvertTimeFromUtc(context.NextFireTimeUtc.Value.DateTime, TimeZoneInfo.Local)); } }
public void ProcessJob(object state) { TriggerFiredBundle bundle = state as TriggerFiredBundle; Trigger trigger = bundle.Trigger; IScheduledJob job = bundle.Job; while (true) { JobExecutionException result = null; ScheduledJobContext context = new ScheduledJobContext(); try { job.Execute(context); } catch (JobExecutionException exception2) { result = exception2; log.Info(string.Format(CultureInfo.InvariantCulture, "Job {0} threw a JobExecutionException: ", new object[] { job.Name }), exception2); } catch (Exception exception3) { log.Error(string.Format(CultureInfo.InvariantCulture, "Job {0} threw an unhandled Exception: ", new object[] { job.Name }), exception3); SchedulerException cause = new SchedulerException("Job threw an unhandled exception.", exception3) { ErrorCode = 800 }; result = new JobExecutionException(cause, false) { ErrorCode = 800 }; } SchedulerInstruction noInstruction = SchedulerInstruction.NoInstruction; try { noInstruction = trigger.ExecutionComplete(context, result); } catch (Exception) { } if (noInstruction == SchedulerInstruction.ReExecuteJob) { if (log.get_IsDebugEnabled()) { log.Debug("Rescheduling trigger to reexecute"); } } else { this.TriggeredJobComplete(trigger, job, noInstruction); break; } } this.NotifySchedulerThread(); }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken)) { return(Task.Run(() => { /* if (context.GetLogLevel() == Enums.LogLevelType.Nil) * LogsAppendersManager.Instance.Info(trigger.GetType(), MethodBase.GetCurrentMethod(), "Trigger " + trigger.Key + " Completed"); * else * LogsAppendersManager.Instance.ConfiguredLog(context.GetLogLevel(), trigger.GetType(), MethodBase.GetCurrentMethod(), "Trigger " + trigger.Key + " Completed"); */ })); }
public void TriggerComplete(Trigger trigger, JobExecutionContext context, SchedulerInstruction triggerInstructionCode) { if (!ShouldDispatch(trigger)) { return; } foreach (ITriggerListener l in listeners) { l.TriggerComplete(trigger, context, triggerInstructionCode); } }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { try { //_log.Info(string.Format("The scheduler called {0} for trigger {1}", MethodBase.GetCurrentMethod().Name, trigger.Key)); //Console.WriteLine(string.Format("TriggerFired - The scheduler called {0} for trigger {1} - {2}", MethodBase.GetCurrentMethod().Name, trigger.Key, context.ToString())); Console.WriteLine(string.Format("The scheduler called [{0}] for trigger {1}", MethodBase.GetCurrentMethod().Name, trigger.Key)); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } }
/// <summary> /// Job completion time call /// </summary> /// <param name="trigger">trigger</param> /// <param name="context">context</param> /// <param name="triggerInstructionCode"></param> public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken)) { return(Task.Run(() => { TaskUtil task = (TaskUtil)context.JobDetail.JobDataMap.Get("TaskParam"); if (task.TriggerComplete != null) { task.NextRunTime = TimeZoneInfo.ConvertTimeFromUtc(context.NextFireTimeUtc.Value.DateTime, TimeZoneInfo.Local); object[] obj = { trigger, context, task }; task.TriggerComplete.Invoke(null, obj); } })); }
/// <summary> /// Called by the <see cref="IScheduler" /> when a <see cref="ITrigger" /> /// has fired, it's associated <see cref="IJobDetail" /> /// has been executed, and it's <see cref="IOperableTrigger.Triggered" /> method has been /// called. /// </summary> /// <param name="trigger">The <see cref="ITrigger" /> that was fired.</param> /// <param name="context">The <see cref="IJobExecutionContext" /> that was passed to the /// <see cref="IJob" />'s <see cref="IJob.Execute" /> method.</param> /// <param name="triggerInstructionCode">The result of the call on the <see cref="IOperableTrigger" />'s <see cref="IOperableTrigger.Triggered" /> method.</param> /// <param name="cancellationToken">The cancellation instruction.</param> public virtual Task TriggerComplete( ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { if (!IsInfoEnabled) { return(Task.CompletedTask); } string instrCode = "UNKNOWN"; if (triggerInstructionCode == SchedulerInstruction.DeleteTrigger) { instrCode = "DELETE TRIGGER"; } else if (triggerInstructionCode == SchedulerInstruction.NoInstruction) { instrCode = "DO NOTHING"; } else if (triggerInstructionCode == SchedulerInstruction.ReExecuteJob) { instrCode = "RE-EXECUTE JOB"; } else if (triggerInstructionCode == SchedulerInstruction.SetAllJobTriggersComplete) { instrCode = "SET ALL OF JOB'S TRIGGERS COMPLETE"; } else if (triggerInstructionCode == SchedulerInstruction.SetTriggerComplete) { instrCode = "SET THIS TRIGGER COMPLETE"; } object?[] args = { trigger.Key.Name, trigger.Key.Group, trigger.GetPreviousFireTimeUtc(), trigger.GetNextFireTimeUtc(), SystemTime.UtcNow(), context.JobDetail.Key.Name, context.JobDetail.Key.Group, context.RefireCount, triggerInstructionCode, instrCode }; WriteInfo(string.Format(CultureInfo.InvariantCulture, TriggerCompleteMessage, args)); return(Task.CompletedTask); }
public void ProcessJob(object state) { TriggerFiredBundle bundle = state as TriggerFiredBundle; Trigger trigger = bundle.Trigger; IScheduledJob job = bundle.Job; do { JobExecutionException jobExecutionException = null; ScheduledJobContext scheduledJobContext = new ScheduledJobContext(); try { job.Execute(scheduledJobContext); } catch (JobExecutionException jee) { jobExecutionException = jee; log.Info(string.Format(CultureInfo.InvariantCulture, "Job {0} threw a JobExecutionException: ", job.Name), jee); } catch (Exception ex) { log.Error(string.Format(CultureInfo.InvariantCulture, "Job {0} threw an unhandled Exception: ", job.Name), ex); SchedulerException se = new SchedulerException("Job threw an unhandled exception.", ex); se.ErrorCode = SchedulerException.ErrorJobExecutionThrewException; jobExecutionException = new JobExecutionException(se, false); jobExecutionException.ErrorCode = JobExecutionException.ErrorJobExecutionThrewException; } SchedulerInstruction instCode = SchedulerInstruction.NoInstruction; try { instCode = trigger.ExecutionComplete(scheduledJobContext, jobExecutionException); } catch (Exception) { // If this happens, there's a bug in the trigger... } // update job/trigger or re-Execute job if (instCode == SchedulerInstruction.ReExecuteJob) { if (log.IsDebugEnabled) { log.Debug("Rescheduling trigger to reexecute"); } continue; } TriggeredJobComplete(trigger, job, instCode); break; } while (true); NotifySchedulerThread(); }
public void TriggeredJobComplete(Trigger trigger, IScheduledJob job, SchedulerInstruction triggerInstCode) { lock (this._triggerLock) { JobWrapper wrapper = this._jobsDictionary[job.Name] as JobWrapper; TriggerWrapper wrapper2 = this._triggersDictionary[trigger.Name] as TriggerWrapper; this._blockedJobs.Remove(job.Name); if (wrapper2 != null) { if (triggerInstCode == SchedulerInstruction.DeleteTrigger) { if (!trigger.GetNextFireTimeUtc().HasValue) { if (!wrapper2.Trigger.GetNextFireTimeUtc().HasValue) { this.RemoveTrigger(trigger.Name); } else { log.Debug("Deleting cancelled - trigger still active"); } } else { this.RemoveTrigger(trigger.Name); } } else if (triggerInstCode == SchedulerInstruction.SetTriggerComplete) { wrapper2.State = InternalTriggerState.Complete; this._timeTriggers.Remove(wrapper2); } else if (triggerInstCode == SchedulerInstruction.SetTriggerError) { log.Info(string.Format(CultureInfo.InvariantCulture, "Trigger {0} set to ERROR state.", new object[] { trigger.Name })); wrapper2.State = InternalTriggerState.Error; } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersError) { log.Info(string.Format(CultureInfo.InvariantCulture, "All triggers of Job {0} set to ERROR state.", new object[] { trigger.Name })); this.SetAllTriggersOfJobToState(trigger.Name, InternalTriggerState.Error); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersComplete) { this.SetAllTriggersOfJobToState(trigger.Name, InternalTriggerState.Complete); } } } }
/// <summary> /// Job完成时调用 /// </summary> /// <param name="trigger">触发器</param> /// <param name="context">上下文</param> /// <param name="triggerInstructionCode"></param> public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { //DependencyConfig.Register(); //using (var timeScope = DependencyConfig.Container.BeginLifetimeScope()) //{ // var jobTaskRepository = timeScope.Resolve<IJobTaskRepository>(); // var jobTask = jobTaskRepository.GetByTaskId(trigger.JobKey.Name); // if (jobTask != null) // { // jobTask.LastRunTime = TimeZoneInfo.ConvertTimeFromUtc(context.NextFireTimeUtc.Value.DateTime, // TimeZoneInfo.Local); // jobTaskRepository.Save(jobTask); // } //} }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) { return(Task.Factory.StartNew(() => { var jobName = context.JobDetail.Key.Name; var msg = $"jobName:{jobName},Job: {context.JobDetail.Key} Name={Name},TriggerComplete"; Singleton <MangerLog> .Instance.Error(msg); Console.WriteLine(msg); _logmsg.Insert(new logMsg { JobName = jobName, Msg = msg }); })); }
public void TriggerComplete(Trigger trigger, JobExecutionContext context, SchedulerInstruction triggerInstructionCode) { if (!trigger.Name.Equals("TimerTrigger")) { Account account = (Account)trigger.JobDataMap.Get("account"); if (account != null) { SimpleTrigger triggerObject = new SimpleTrigger(account.Login + "Trigger", "account", DateTime.MinValue, null, 0, TimeSpan.Zero); triggerObject.JobName = account.Login + "Job"; triggerObject.StartTimeUtc = DateTime.UtcNow.AddSeconds(new Random().Next(account.Settings.NextTimeLoginMin, account.Settings.NextTimeLoginMax)); account.SchedulerTrigger = triggerObject; triggerObject.JobDataMap.Add("account", account); m_accountManager.SetNextLoginTimeForAccount(account); } } }
/// <summary> /// 触发完成 /// </summary> /// <param name="trigger"></param> /// <param name="context"></param> /// <param name="triggerInstructionCode"></param> public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { var currentTriggerState = QuartzManager.Scheduler.GetTriggerState(trigger.Key).ToString().ToUpper(); if ("COMPLETE".Equals(currentTriggerState)) { LogHelper.Info($"【TriggerComplete】:触发器 {trigger.Key.Name} 触发【TriggerComplete】完成 MonitorTriggerListener.TriggerComplete"); } try { LogHelper.Info($"【TriggerComplete】:触发器 {trigger.Key.Name} 触发【TriggerComplete】完成 MonitorTriggerListener.TriggerComplete"); } catch (Exception ex) { LogHelper.Error($"MonitorTriggerListener.TriggerComplete 异常,当前 Trigger:{ trigger.Key.Name }", ex); } }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { try { //var executationDuration = (DateTime.UtcNow - trigger.GetPreviousFireTimeUtc()).Value.TotalSeconds; var executionDuration = context.JobRunTime.TotalSeconds; TriggerStatistic triggerStat = new TriggerStatistic() { Group = trigger.Key.Group, JobKey = trigger.JobKey.Name, TriggerKey = trigger.Key.Name, ExecutionDurationInSeconds = executionDuration, StartTime = trigger.GetPreviousFireTimeUtc().Value.DateTime.ToLocalTime(), FinishTime = DateTime.Now }; Sitecore.Diagnostics.Log.Info(String.Format("Job {0} with trigger {1} Completed @ {2} and it took {3} seconds ", triggerStat.JobKey, triggerStat.TriggerKey, DateTime.Now, triggerStat.ExecutionDurationInSeconds), this); string triggerStatProviderType = Settings.GetSetting("Sitecore.QuartzScheduler.TriggerStatisticsStoreProvider"); if (!String.IsNullOrEmpty(triggerStatProviderType)) { var triggerStatsProvider = Activator.CreateInstance(Type.GetType(triggerStatProviderType)) as ITriggerStatisticsStore; triggerStatsProvider.SaveTriggerStatistic(triggerStat); } else { Sitecore.Diagnostics.Log.Warn("Sitecore.QuartzScheuler: Missing App Setting value for Sitecore.QuartzScheduler.TriggerStatisticsStoreProvider", this); } } catch(Exception ex) { Sitecore.Diagnostics.Log.Error("Exception in TriggerComplete: " + ex.Message + Environment.NewLine + ex.StackTrace, this); } }
public virtual void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { throw new NotImplementedException(); }
protected virtual void TriggeredJobComplete(ConnectionAndTransactionHolder conn, IOperableTrigger trigger, IJobDetail jobDetail, SchedulerInstruction triggerInstCode) { try { if (triggerInstCode == SchedulerInstruction.DeleteTrigger) { if (!trigger.GetNextFireTimeUtc().HasValue) { // double check for possible reschedule within job // execution, which would cancel the need to delete... TriggerStatus stat = Delegate.SelectTriggerStatus(conn, trigger.Key); if (stat != null && !stat.NextFireTimeUtc.HasValue) { RemoveTrigger(conn, trigger.Key); } } else { RemoveTrigger(conn, trigger.Key); SignalSchedulingChangeOnTxCompletion(null); } } else if (triggerInstCode == SchedulerInstruction.SetTriggerComplete) { Delegate.UpdateTriggerState(conn, trigger.Key, StateComplete); SignalSchedulingChangeOnTxCompletion(null); } else if (triggerInstCode == SchedulerInstruction.SetTriggerError) { Log.Info("Trigger " + trigger.Key + " set to ERROR state."); Delegate.UpdateTriggerState(conn, trigger.Key, StateError); SignalSchedulingChangeOnTxCompletion(null); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersComplete) { Delegate.UpdateTriggerStatesForJob(conn, trigger.JobKey, StateComplete); SignalSchedulingChangeOnTxCompletion(null); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersError) { Log.Info("All triggers of Job " + trigger.JobKey + " set to ERROR state."); Delegate.UpdateTriggerStatesForJob(conn, trigger.JobKey, StateError); SignalSchedulingChangeOnTxCompletion(null); } if (jobDetail.ConcurrentExecutionDisallowed) { Delegate.UpdateTriggerStatesForJobFromOtherState(conn, jobDetail.Key, StateWaiting, StateBlocked); Delegate.UpdateTriggerStatesForJobFromOtherState(conn, jobDetail.Key, StatePaused, StatePausedBlocked); SignalSchedulingChangeOnTxCompletion(null); } if (jobDetail.PersistJobDataAfterExecution) { try { if (jobDetail.JobDataMap.Dirty) { Delegate.UpdateJobData(conn, jobDetail); } } catch (IOException e) { throw new JobPersistenceException("Couldn't serialize job data: " + e.Message, e); } catch (Exception e) { throw new JobPersistenceException("Couldn't update job data: " + e.Message, e); } } } catch (Exception e) { throw new JobPersistenceException("Couldn't update trigger state(s): " + e.Message, e); } try { Delegate.DeleteFiredTrigger(conn, trigger.FireInstanceId); } catch (Exception e) { throw new JobPersistenceException("Couldn't delete fired trigger: " + e.Message, e); } }
/// <summary> /// Called by the <see cref="IScheduler" /> when a <see cref="ITrigger" /> /// has fired, it's associated <see cref="IJobDetail" /> /// has been executed, and it's <see cref="IOperableTrigger.Triggered" /> method has been /// called. /// </summary> /// <param name="trigger">The <see cref="ITrigger" /> that was fired.</param> /// <param name="context">The <see cref="IJobExecutionContext" /> that was passed to the /// <see cref="IJob" />'s <see cref="IJob.Execute" /> method.</param> /// <param name="triggerInstructionCode">The result of the call on the <see cref="IOperableTrigger" />'s <see cref="IOperableTrigger.Triggered" /> method.</param> public virtual void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { string instrCode = "UNKNOWN"; if (triggerInstructionCode == SchedulerInstruction.DeleteTrigger) { instrCode = "DELETE TRIGGER"; } else if (triggerInstructionCode == SchedulerInstruction.NoInstruction) { instrCode = "DO NOTHING"; } else if (triggerInstructionCode == SchedulerInstruction.ReExecuteJob) { instrCode = "RE-EXECUTE JOB"; } else if (triggerInstructionCode ==SchedulerInstruction.SetAllJobTriggersComplete) { instrCode = "SET ALL OF JOB'S TRIGGERS COMPLETE"; } else if (triggerInstructionCode == SchedulerInstruction.SetTriggerComplete) { instrCode = "SET THIS TRIGGER COMPLETE"; } object[] args = new object[] { trigger.Key.Name, trigger.Key.Group, trigger.GetPreviousFireTimeUtc(), trigger.GetNextFireTimeUtc(), SystemTime.UtcNow(), context.JobDetail.Key.Name, context.JobDetail.Key.Group, context.RefireCount, triggerInstructionCode, instrCode }; }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { return TaskUtil.CompletedTask; }
/// <summary> /// Inform the <see cref="IJobStore" /> that the scheduler has completed the /// firing of the given <see cref="ITrigger" /> (and the execution its /// associated <see cref="IJob" />), and that the <see cref="JobDataMap" /> /// in the given <see cref="IJobDetail" /> should be updated if the <see cref="IJob" /> /// is stateful. /// </summary> public virtual void TriggeredJobComplete(IOperableTrigger trigger, IJobDetail jobDetail, SchedulerInstruction triggerInstCode) { ExecuteInNonManagedTXLock(LockTriggerAccess, conn => TriggeredJobComplete(conn, trigger, jobDetail, triggerInstCode)); }
/// <summary> /// Inform the <see cref="IJobStore" /> that the scheduler has completed the /// firing of the given <see cref="Trigger" /> (and the execution its /// associated <see cref="IJob" />), and that the <see cref="JobDataMap" /> /// in the given <see cref="JobDetail" /> should be updated if the <see cref="IJob" /> /// is stateful. /// </summary> public virtual void TriggeredJobComplete(SchedulingContext ctxt, Trigger trigger, JobDetail jobDetail, SchedulerInstruction triggerInstCode) { ExecuteInNonManagedTXLock(LockTriggerAccess, new TriggeredJobCompleteCallback(this, ctxt, trigger, triggerInstCode, jobDetail)); }
protected internal void NotifyJobStoreJobVetoed(IOperableTrigger trigger, IJobDetail detail, SchedulerInstruction instCode) { resources.JobStore.TriggeredJobComplete(trigger, detail, instCode); }
private bool NotifyTriggerListenersComplete(JobExecutionContext ctx, SchedulerInstruction instCode) { try { qs.NotifyTriggerListenersComplete(ctx, instCode); } catch (SchedulerException se) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "Unable to notify TriggerListener(s) of Job that was executed: (error will be ignored). trigger= {0} job= {1}", ctx.Trigger.FullName, ctx.JobDetail.FullName), se); return false; } if (!ctx.Trigger.GetNextFireTimeUtc().HasValue) { qs.NotifySchedulerListenersFinalized(ctx.Trigger); } return true; }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { Write("{0} -- {1} -- Trigger ({2}) completed", Name, DateTime.Now, trigger.Key); }
/// <summary> /// Notifies the job store job complete. /// </summary> /// <param name="ctxt">The job scheduling context.</param> /// <param name="trigger">The trigger.</param> /// <param name="detail">The detail.</param> /// <param name="instCode">The instruction code.</param> protected internal virtual void NotifyJobStoreJobComplete(SchedulingContext ctxt, Trigger trigger, JobDetail detail, SchedulerInstruction instCode) { resources.JobStore.TriggeredJobComplete(ctxt, trigger, detail, instCode); }
/// <summary> /// Notifies the trigger listeners of completion. /// </summary> /// <param name="jec">The job executution context.</param> /// <param name="instCode">The instruction code to report to triggers.</param> public virtual void NotifyTriggerListenersComplete(JobExecutionContext jec, SchedulerInstruction instCode) { // build a list of all trigger listeners that are to be notified... IList listeners = BuildTriggerListenerList(jec.Trigger.TriggerListenerNames); // notify all trigger listeners in the list foreach (ITriggerListener tl in listeners) { try { tl.TriggerComplete(jec.Trigger, jec, instCode); } catch (Exception e) { SchedulerException se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "TriggerListener '{0}' threw exception: {1}", tl.Name, e.Message), e); se.ErrorCode = SchedulerException.ErrorTriggerListener; throw se; } } }
/// <summary> /// Completes the trigger retry loop. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="jobDetail">The job detail.</param> /// <param name="instCode">The inst code.</param> /// <returns></returns> public virtual bool CompleteTriggerRetryLoop(IOperableTrigger trigger, IJobDetail jobDetail, SchedulerInstruction instCode) { long count = 0; while (!shutdownRequested && !qs.IsShuttingDown) { try { Thread.Sleep(qs.DbRetryInterval); // retry per config setting (the db connection must be failed) qs.NotifyJobStoreJobComplete(trigger, jobDetail, instCode); return true; } catch (JobPersistenceException jpe) { if (count % 4 == 0) qs.NotifySchedulerListenersError( "An error occured while marking executed job complete (will continue attempts). job= '" + jobDetail.Key + "'", jpe); } catch (ThreadInterruptedException) { } count++; } return false; }
/// <summary> /// Vetoeds the job retry loop. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="jobDetail">The job detail.</param> /// <param name="instCode">The inst code.</param> /// <returns></returns> public bool VetoedJobRetryLoop(IOperableTrigger trigger, IJobDetail jobDetail, SchedulerInstruction instCode) { while (!shutdownRequested) { try { Thread.Sleep(qs.DbRetryInterval); // retry per config setting (the db connection must be failed) qs.NotifyJobStoreJobVetoed(trigger, jobDetail, instCode); return true; } catch (JobPersistenceException jpe) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while marking executed job vetoed. job= '{0}'", jobDetail.Key), jpe); } catch (ThreadInterruptedException) { } } return false; }
/// <summary> /// Notifies the job store job complete. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="detail">The detail.</param> /// <param name="instCode">The instruction code.</param> public virtual void NotifyJobStoreJobComplete(IOperableTrigger trigger, IJobDetail detail, SchedulerInstruction instCode) { resources.JobStore.TriggeredJobComplete(trigger, detail, instCode); }
public Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { return Task.WhenAll(listeners.Select(l => l.TriggerComplete(trigger, context, triggerInstructionCode))); }
/// <summary> /// Vetoeds the job retry loop. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="jobDetail">The job detail.</param> /// <param name="instCode">The inst code.</param> /// <returns></returns> public bool VetoedJobRetryLoop(Trigger trigger, JobDetail jobDetail, SchedulerInstruction instCode) { while (!shutdownRequested) { try { Thread.Sleep(5 * 1000); // retry every 5 seconds (the db // connection must be failed) qs.NotifyJobStoreJobVetoed(schdCtxt, trigger, jobDetail, instCode); return true; } catch (JobPersistenceException jpe) { qs.NotifySchedulerListenersError( string.Format(CultureInfo.InvariantCulture, "An error occured while marking executed job vetoed. job= '{0}'", jobDetail.FullName), jpe); } catch (ThreadInterruptedException) { } } return false; }
public TriggeredJobCompleteCallback(JobStoreSupport js, SchedulingContext ctxt, Trigger trigger, SchedulerInstruction triggerInstCode, JobDetail jobDetail) : base(js) { this.ctxt = ctxt; this.trigger = trigger; this.triggerInstCode = triggerInstCode; this.jobDetail = jobDetail; }
public virtual void TriggerComplete(Trigger trigger, JobExecutionContext context, SchedulerInstruction triggerInstructionCode) { }
/// <summary> /// Completes the trigger retry loop. /// </summary> /// <param name="trigger">The trigger.</param> /// <param name="jobDetail">The job detail.</param> /// <param name="instCode">The inst code.</param> /// <returns></returns> public virtual bool CompleteTriggerRetryLoop(Trigger trigger, JobDetail jobDetail, SchedulerInstruction instCode) { long count = 0; while (!shutdownRequested) { // FIXME: jhouse: note that there is no longer anthing that calls requestShutdown() try { Thread.Sleep(TimeSpan.FromSeconds(15)); // retry every 15 seconds (the db // connection must be failed) qs.NotifyJobStoreJobComplete(schdCtxt, trigger, jobDetail, instCode); return true; } catch (JobPersistenceException jpe) { if (count % 4 == 0) qs.NotifySchedulerListenersError( "An error occured while marking executed job complete (will continue attempts). job= '" + jobDetail.FullName + "'", jpe); } catch (ThreadInterruptedException) { } count++; } return false; }
/// <summary> /// Inform the <see cref="IJobStore" /> that the scheduler has completed the /// firing of the given <see cref="ITrigger" /> (and the execution its /// associated <see cref="IJob" />), and that the <see cref="JobDataMap" /> /// in the given <see cref="IJobDetail" /> should be updated if the <see cref="IJob" /> /// is stateful. /// </summary> public virtual void TriggeredJobComplete(IOperableTrigger trigger, IJobDetail jobDetail, SchedulerInstruction triggerInstCode) { lock (lockObject) { this.ReleaseAcquiredTrigger(trigger); // It's possible that the job is null if: // 1- it was deleted during execution // 2- RAMJobStore is being used only for volatile jobs / triggers // from the JDBC job store if (jobDetail.PersistJobDataAfterExecution) { this.Jobs.Update( Query.EQ("_id", jobDetail.Key.ToBsonDocument()), Update.Set("JobDataMap", jobDetail.JobDataMap.ToBsonDocument())); } if (jobDetail.ConcurrentExecutionDisallowed) { IList<Spi.IOperableTrigger> jobTriggers = this.GetTriggersForJob(jobDetail.Key); IEnumerable<BsonDocument> triggerKeys = jobTriggers.Select(t => t.Key.ToBsonDocument()); this.Triggers.Update( Query.And( Query.In("_id", triggerKeys), Query.EQ("State", "Blocked")), Update.Set("State", "Waiting")); this.Triggers.Update( Query.And( Query.In("_id", triggerKeys), Query.EQ("State", "PausedAndBlocked")), Update.Set("State", "Paused")); signaler.SignalSchedulingChange(null); } // even if it was deleted, there may be cleanup to do this.BlockedJobs.Remove( Query.EQ("_id", jobDetail.Key.ToBsonDocument())); // check for trigger deleted during execution... if (triggerInstCode == SchedulerInstruction.DeleteTrigger) { log.Debug("Deleting trigger"); DateTimeOffset? d = trigger.GetNextFireTimeUtc(); if (!d.HasValue) { // double check for possible reschedule within job // execution, which would cancel the need to delete... d = trigger.GetNextFireTimeUtc(); if (!d.HasValue) { this.RemoveTrigger(trigger.Key); } else { log.Debug("Deleting cancelled - trigger still active"); } } else { this.RemoveTrigger(trigger.Key); signaler.SignalSchedulingChange(null); } } else if (triggerInstCode == SchedulerInstruction.SetTriggerComplete) { this.Triggers.Update( Query.EQ("_id", trigger.Key.ToBsonDocument()), Update.Set("State", "Complete")); signaler.SignalSchedulingChange(null); } else if (triggerInstCode == SchedulerInstruction.SetTriggerError) { Log.Info(string.Format(CultureInfo.InvariantCulture, "Trigger {0} set to ERROR state.", trigger.Key)); this.Triggers.Update( Query.EQ("_id", trigger.Key.ToBsonDocument()), Update.Set("State", "Error")); signaler.SignalSchedulingChange(null); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersError) { Log.Info(string.Format(CultureInfo.InvariantCulture, "All triggers of Job {0} set to ERROR state.", trigger.JobKey)); IList<Spi.IOperableTrigger> jobTriggers = this.GetTriggersForJob(jobDetail.Key); IEnumerable<BsonDocument> triggerKeys = jobTriggers.Select(t => t.Key.ToBsonDocument()); this.Triggers.Update( Query.In("_id", triggerKeys), Update.Set("State", "Error")); signaler.SignalSchedulingChange(null); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersComplete) { IList<Spi.IOperableTrigger> jobTriggers = this.GetTriggersForJob(jobDetail.Key); IEnumerable<BsonDocument> triggerKeys = jobTriggers.Select(t => t.Key.ToBsonDocument()); this.Triggers.Update( Query.In("_id", triggerKeys), Update.Set("State", "Complete")); signaler.SignalSchedulingChange(null); } } }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { }
/// <summary> /// Inform the <see cref="T:Quartz.Spi.IJobStore"/> that the scheduler has completed the /// firing of the given <see cref="T:Quartz.ITrigger"/> (and the execution its /// associated <see cref="T:Quartz.IJob"/>), and that the <see cref="T:Quartz.JobDataMap"/> /// in the given <see cref="T:Quartz.IJobDetail"/> should be updated if the <see cref="T:Quartz.IJob"/> /// is stateful. /// </summary> public override void TriggeredJobComplete(IOperableTrigger trigger, IJobDetail jobDetail, SchedulerInstruction triggerInstCode) { var jobHashKey = this.RedisJobStoreSchema.JobHashKey(jobDetail.Key); var jobDataMapHashKey = this.RedisJobStoreSchema.JobDataMapHashKey(jobDetail.Key); var triggerHashKey = this.RedisJobStoreSchema.TriggerHashkey(trigger.Key); if (this.Db.KeyExists(jobHashKey)) { Logger.InfoFormat("{0} - Job has completed", jobHashKey); if (jobDetail.PersistJobDataAfterExecution) { var jobDataMap = jobDetail.JobDataMap; Db.KeyDelete(jobDataMapHashKey); if (jobDataMap != null && !jobDataMap.IsEmpty) { Db.HashSet(jobDataMapHashKey, ConvertToHashEntries(jobDataMap)); } } if (jobDetail.ConcurrentExecutionDisallowed) { Db.SetRemove(this.RedisJobStoreSchema.BlockedJobsSet(), jobHashKey); Db.KeyDelete(this.RedisJobStoreSchema.JobBlockedKey(jobDetail.Key)); var jobTriggersSetKey = this.RedisJobStoreSchema.JobTriggersSetKey(jobDetail.Key); foreach (var nonConcurrentTriggerHashKey in this.Db.SetMembers(jobTriggersSetKey)) { var score = this.Db.SortedSetScore(this.RedisJobStoreSchema.TriggerStateSetKey(RedisTriggerState.Blocked), nonConcurrentTriggerHashKey); if (score.HasValue) { this.SetTriggerState(RedisTriggerState.Paused, score.Value, nonConcurrentTriggerHashKey); } else { score = this.Db.SortedSetScoreAsync( this.RedisJobStoreSchema.TriggerStateSetKey(RedisTriggerState.PausedBlocked), nonConcurrentTriggerHashKey).Result; if (score.HasValue) { this.SetTriggerState(RedisTriggerState.Paused, score.Value, nonConcurrentTriggerHashKey); } } } this.SchedulerSignaler.SignalSchedulingChange(null); } } else { this.Db.SetRemove(this.RedisJobStoreSchema.BlockedJobsSet(), jobHashKey); } if (this.Db.KeyExists(triggerHashKey)) { if (triggerInstCode == SchedulerInstruction.DeleteTrigger) { if (trigger.GetNextFireTimeUtc().HasValue == false) { if (string.IsNullOrEmpty(this.Db.HashGet(triggerHashKey, RedisJobStoreSchema.NextFireTime))) { RemoveTrigger(trigger.Key); } } else { this.RemoveTrigger(trigger.Key); this.SchedulerSignaler.SignalSchedulingChange(null); } } else if (triggerInstCode == SchedulerInstruction.SetTriggerComplete) { this.SetTriggerState(RedisTriggerState.Completed, DateTimeOffset.UtcNow.DateTime.ToUnixTimeMilliSeconds(), triggerHashKey); this.SchedulerSignaler.SignalSchedulingChange(null); } else if (triggerInstCode == SchedulerInstruction.SetTriggerError) { double score = trigger.GetNextFireTimeUtc().HasValue ? trigger.GetNextFireTimeUtc().Value.DateTime.ToUnixTimeMilliSeconds() : 0; this.SetTriggerState(RedisTriggerState.Error, score, triggerHashKey); this.SchedulerSignaler.SignalSchedulingChange(null); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersError) { var jobTriggersSetKey = this.RedisJobStoreSchema.JobTriggersSetKey(jobDetail.Key); foreach (var errorTriggerHashKey in this.Db.SetMembersAsync(jobTriggersSetKey).Result) { var nextFireTime = this.Db.HashGetAsync(errorTriggerHashKey.ToString(), RedisJobStoreSchema.NextFireTime).Result; var score = string.IsNullOrEmpty(nextFireTime) ? 0 : double.Parse(nextFireTime); this.SetTriggerState(RedisTriggerState.Error, score, errorTriggerHashKey); } this.SchedulerSignaler.SignalSchedulingChange(null); } else if (triggerInstCode == SchedulerInstruction.SetAllJobTriggersComplete) { var jobTriggerSetKey = this.RedisJobStoreSchema.JobTriggersSetKey(jobDetail.Key); foreach (var completedTriggerHashKey in this.Db.SetMembersAsync(jobTriggerSetKey).Result) { this.SetTriggerState(RedisTriggerState.Completed, DateTimeOffset.UtcNow.DateTime.ToUnixTimeMilliSeconds(), completedTriggerHashKey); } this.SchedulerSignaler.SignalSchedulingChange(null); } } }
/// <summary> /// Notifies the trigger listeners of completion. /// </summary> /// <param name="jec">The job executution context.</param> /// <param name="instCode">The instruction code to report to triggers.</param> public virtual void NotifyTriggerListenersComplete(IJobExecutionContext jec, SchedulerInstruction instCode) { // build a list of all trigger listeners that are to be notified... IEnumerable<ITriggerListener> listeners = BuildTriggerListenerList(); // notify all trigger listeners in the list foreach (ITriggerListener tl in listeners) { if (!MatchTriggerListener(tl, jec.Trigger.Key)) { continue; } try { tl.TriggerComplete(jec.Trigger, jec, instCode); } catch (Exception e) { SchedulerException se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "TriggerListener '{0}' threw exception: {1}", tl.Name, e.Message), e); throw se; } } }
public override void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { entries.Add(new LogEntry("Job complete: " + Describe(context))); }
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode) { var msg = string.Format("触发器 {0} / {1} , 任务 {2} / {3} 执行完毕", trigger.Key.Name, trigger.Key.Name, trigger.JobKey.Name, trigger.JobKey.Group); this.Send(msg); }