/// <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; }
/// <summary> /// 开启job /// </summary> /// <param name="jobParam">job执行参数</param> /// <param name="onceJob">是否执行计划外的任务</param> /// <returns></returns> public bool StartJob(JobMeta jobParam, bool onceJob = false) { try { var triggerKey = onceJob ? UtilsFunc.GenTriggerKey(jobParam.JobName) : GetTriggerKey(); var trigger = GenTrigger(triggerKey, jobParam.StartTime, jobParam.Interval, jobParam.CronExpression, onceJob); if (trigger == null) { JobLogHelper.Error( $"创建{jobParam.JobName}的trigger失败,参数为{onceJob},{jobParam.StartTime},{jobParam.Interval},{jobParam.CronExpression}", null, nameof(StartJob)); return(false); } var jobkey = onceJob ? UtilsFunc.GenJobKey(jobParam.JobName) : GetJobKey(); var job = JobBuilder.Create <T>() .WithIdentity(jobkey) .Build(); job.SetJobName(jobParam.JobName); job.SetJobCode(jobParam.JobCode); job.SetOnceJobFlag(onceJob); job.SetDepJobs(jobParam.DepJobs); job.SetJobRunParams(jobParam.RunParams); job.SetAutoClose(jobParam.AutoClose); job.SetIsDoNotice(jobParam.IsDoNotice); ScheduleModConfig.Instance.DefaultScheduler.ScheduleJob(job, trigger); var jobListener = new LT(); if (onceJob) { jobListener.SetName(UtilsFunc.GenListenerName(jobParam.JobName)); } ScheduleModConfig.Instance.DefaultScheduler.ListenerManager.AddJobListener(jobListener, KeyMatcher <JobKey> .KeyEquals(jobkey)); ScheduleModConfig.Instance.DefaultScheduler.ListenerManager.AddTriggerListener(jobListener, KeyMatcher <TriggerKey> .KeyEquals(triggerKey)); if (jobParam.State == JobStateEnum.Pause) { ScheduleModConfig.Instance.DefaultScheduler.PauseJob(jobkey); } return(true); } catch (Exception ex) { JobLogHelper.Error(ex.Message, ex, nameof(StartJob)); return(false); } }
/// <summary> /// 在Job执行前调用 /// Called by the Quartz.IScheduler when a Quartz.IJobDetail is about to be executed /// (an associated Quartz.ITrigger has occurred). /// This method will not be invoked if the execution of the Job was vetoed by a Quartz.ITriggerListener. /// </summary> /// <param name="context"> /// The Quartz.IJobExecutionContext that will be passed to the /// Quartz.IJob'sQuartz.IJob.Execute(Quartz.IJobExecutionContext) method. /// </param> /// <param name="cancellationToken"> The cancellation instruction.</param> /// <returns></returns> public virtual async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default) { Debug(nameof(IJobListener), nameof(JobToBeExecuted)); try { var jobName = context.GetJobName(); var jobCode = context.GetJobCode(); var autoClose = context.GetAutoClose(); var runParams = context.GetJobRunParams(); var msg = $"{JobInfo} begin time:{DateTime.Now:yyyy-MM-dd HH:mm:sss}, autoClose:{autoClose}, runParams:{runParams}"; JobLogHelper.Info(msg, nameof(JobToBeExecuted)); // 检查依赖选项是否满足 // var isOnceJob = JobContextFunc.IsOnceJob(context); // var depJobs = JobContextFunc.GetDepJobs(context); // var isContinueRun = (isOnceJob || string.IsNullOrEmpty(depJobs)) ? true : WaitJobCompleted(origJobName, depJobs.Split(',').ToList(), DateTime.Now.Date); //JobContextFunc.SetContinueRunFlag(context.JobDetail, isContinueRun); //记录任务开始执行 // var jobParam = GetJobMeta(JobContextFunc.GetOrigJobName(context)); var ctrl = Ioc.GetService <IScheduleOrderCtrl>(); if (ctrl != null) { await ctrl.StartJobSafety(JobId, jobName, jobCode, runParams); } /* * * //TODO do job run log * ScheduleOrderCtrl ctrl = new ScheduleOrderCtrl(); * var jobId = ctrl.StartJobSafety(jobName, origJobName, runParams); * JobContextFunc.SetJobDbId(context.JobDetail, jobId.ToString()); */ //remove to TriggerFired do this. // JobContextFunc.SetJobDbId(context.JobDetail, GuidHelper.GetGuid()); } catch (Exception ex) { JobLogHelper.Error($"{JobInfo}:JobToBeExecuted Error {ex}", ex, nameof(JobToBeExecuted)); } // return TaskUtil.CompletedTask; await Task.CompletedTask; }
/// <summary> /// Job完成后调用 /// Called by the Quartz.IScheduler after a Quartz.IJobDetail has been executed, /// and be for the associated Quartz.Spi.IOperableTrigger's Quartz.Spi.IOperableTrigger.Triggered(Quartz.ICalendar) /// method has been called. /// </summary> /// <param name="context"> /// The Quartz.IJobExecutionContext that will be passed to the /// Quartz.IJob'sQuartz.IJob.Execute(Quartz.IJobExecutionContext) method. /// </param> /// <param name="cancellationToken">The cancellation instruction.</param> /// <param name="jobException"></param> /// <returns></returns> public virtual async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default) { Debug(nameof(IJobListener), nameof(JobWasExecuted)); var retCode = 0; try { var jobName = context.GetJobName(); // var jobCode = JobContextFunc.GetJobCode(context); var autoClose = context.GetAutoClose(); var runParams = context.GetJobRunParams(); // 如果是单次运行,则删除job // OnceJob not support now if (context.IsOnceJob()) { var delJobRet = await new ScheduleCtrl().StopJobAsync(jobName); if (delJobRet != JobActionRetEnum.Success) { JobLogHelper.Error( $"{JobInfo}:单次运行job结束后删除job失败,job :{JobContext.CurrentJobBaseInfo},返回结果:{delJobRet }", null, nameof(JobWasExecuted)); } } var jobId = JobId; var jobRunState = JobRunStateEnum.Ok; if (jobException != null) { jobRunState = JobRunStateEnum.Exception; JobLogHelper.Error($"{JobInfo} 发生异常", jobException, nameof(JobWasExecuted)); } else { var jobBusinessState = context.GetJobBusinessState(); switch (jobBusinessState) { case JobBusinessStateEnum.Unknown: //基本上是没有继承BaseJob的 JobLogHelper.Info($"{JobInfo} 获取到Job的业务状态为 {JobBusinessStateEnum.Unknown},可能是该Job 未继承BaseJob ", nameof(JobWasExecuted)); break; case JobBusinessStateEnum.Success: break; case JobBusinessStateEnum.Fail: jobRunState = JobRunStateEnum.BusinessError; break; default: jobRunState = JobRunStateEnum.Error; JobLogHelper.Error( $"{JobInfo} 发生异常,无法获取到Job的业务状态", null, nameof(JobWasExecuted)); break; } } var msg = $"{JobInfo} end time:{DateTime.Now:yyyy-MM-dd HH:mm:sss}, jobRunState:{jobRunState},autoClose:{autoClose}, runParams:{runParams}"; JobLogHelper.Info(msg, nameof(JobWasExecuted)); // DoJobLog var ctrl = Ioc.GetService <IScheduleOrderCtrl>(); if (ctrl != null) { await ctrl.CompleteJobSafety(JobId, jobRunState); } } catch (Exception ex) { JobLogHelper.Info($"{JobInfo}: JobWasExecuted Error {ex}", nameof(JobWasExecuted)); retCode = 1; } finally { var autoClose = JobContextFunc.GetAutoClose(context); if (autoClose) { // TODO 通知注册中心下线 Environment.Exit(retCode); } } await Task.CompletedTask; // return TaskUtil.CompletedTask; }
protected void Debug(string interfaceName, string actionName) { JobLogHelper.Debug($"{JobInfo}:{actionName}:{interfaceName}:NowTicks({DateTime.Now.Ticks})", actionName); }