原文:作业调度框架Quartz.NET-现学现用-02-任务监听

前言

任务调度系统并不是完美的,它会出现任务执行失败的情况。如果你需要处理任务失败后的逻辑,希望这篇笔记可以为你提供些帮助。

Quartz.NET的任务监听系统已经被我运用在已上线的工程中,亲测无坑。

Quartz.Listener

要创建一个监听器,只需创建一个实现ITriggerListener或IJobListener接口的对象。然后在运行时向调度程序注册监听器,并且必须为其指定名称(更确切地说,他们必须通过其Name属性来唯一标识自己。)

关键接口和类

  • IJobListener - 与作业相关的事件包括:作业即将执行的通知,以及作业完成执行时的通知。
  • ITriggerListener - 与触发器相关的事件包括:触发器触发,触发错误触发和触发器完成(触发器触发的作业完成)。
  • ListenerManager - 监听器与调度程序的ListenerManager一起注册,并附带一个Matcher,用于描述监听器想要接收事件的作业/触发器。

示例应用程序

using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using System;
using System.Collections.Specialized;
using System.Threading;
using System.Threading.Tasks; namespace QuarzLis
{
class Program
{
static void Main(string[] args)
{
StartUpJobs.StartUp().GetAwaiter().GetResult();
Console.ReadKey();
} public static class StartUpJobs
{
public static async Task StartUp()
{
try
{
//第一步:从工厂中获取Scheduler实例
NameValueCollection props = new NameValueCollection();
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler();
//第二步:然后运行它
await scheduler.Start();
//第三步:定义作业并绑定到HelloJob类,HelloJob类实现IJob接口
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
//UsingJobData 可以用来传参数
.UsingJobData("appKey", "123456QWE")
.UsingJobData("appName", "小熊猫")
.UsingJobData("api", "https://www.baidu.com")
.Build(); //第四步:创建触发器。设定,执行一次作业。
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1") //指定唯一标识,触发器名字,和组名字
//这对于将作业和触发器组织成“报告作业”和“维护作业”等类别非常有用。
//作业或触发器的键的名称部分在组内必须是唯一的
.StartAt(DateBuilder.FutureDate(5, IntervalUnit.Second)) //可以设定在未来的 5 秒钟后触发
.Build(); //第五步:作业与触发器组合,安排任务
await scheduler.ScheduleJob(job, trigger); //第六步:创建任务监听,用来解决任务执行失败的情况. HelloJob类实现IJobListener接口
IJobListener jobListener = new HelloJob(); // 注: 任务监听是通过 IJobListener.Name 来区分的.以下逻辑避免多个任务监听情况下造成的监听被覆盖.
// a) 获取当前任务监听实例的名称.
var listener = scheduler.ListenerManager.GetJobListener(jobListener.Name);
// b) 通过job.Key 获取该任务在调度系统中的唯一实体
IMatcher<JobKey> matcher = KeyMatcher<JobKey>.KeyEquals(job.Key);
// c) 注意: 任务监听系统中已存在当前任务监听实例,与新添加任务监听的逻辑的区别.
if (listener != null)
{
// 如果已存在该任务监听实例,调用此方法,为该任务监听实例新增监听对象
scheduler.ListenerManager.AddJobListenerMatcher(jobListener.Name, matcher);
}
else
// 任务监听系统中不存在该任务监听实例,则调用此方法新增监听对象
scheduler.ListenerManager.AddJobListener(jobListener, matcher); //创建触发器监听,触发器监听与任务监听同名也不影响
ITriggerListener triggerListener = new HelloJob();
var triListener = scheduler.ListenerManager.GetTriggerListener(triggerListener.Name);
IMatcher<TriggerKey> triMatcher = KeyMatcher<TriggerKey>.KeyEquals(trigger.Key);
if (triListener != null)
{
scheduler.ListenerManager.AddTriggerListenerMatcher(triggerListener.Name, triMatcher);
}
else
scheduler.ListenerManager.AddTriggerListener(triggerListener, triMatcher); //可以设置关闭该调度
//await Task.Delay(TimeSpan.FromSeconds(5));
//await scheduler.Shutdown();
}
catch (SchedulerException se)
{
Console.WriteLine(se);
}
}
} //实现IJobListener 接口,实现 ITriggerListener 接口,这里和 IJob逻辑放在了一起
public class HelloJob : IJob, IJobListener, ITriggerListener
{
private string appKey;
private string appName;
private string appApi; public string Name
{
get;
}
public HelloJob()
{
this.Name = this.GetType().ToString();
}
public HelloJob(string name)
{
this.Name = name;
}
public async Task Execute(IJobExecutionContext context)
{
JobKey jkey = context.JobDetail.Key;
TriggerKey tKey = context.Trigger.Key; JobDataMap dataMap = context.MergedJobDataMap;
appKey = dataMap.GetString("appKey"); //通过键值获取数据
appName = dataMap.GetString("appName");
appApi = dataMap.GetString("api");
await Console.Error.WriteLineAsync(
string.Format("[{0}]开始推送:\nJobKey:{1}\nTriggerKey:{2}\nAppKey:{3} appName: {4} , and AppAPI: {5}"
, DateTime.Now.ToLongTimeString(), jkey, tKey, appKey, appName, appApi));
}
#region IJobListener
public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]任务监听,name:{1}|任务执行失败重新执行。"
, DateTime.Now.ToLongTimeString(), Name));
//任务执行失败,再次执行任务
await Execute(context);
} public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]任务监听,name:{1}|准备执行任务。"
, DateTime.Now.ToLongTimeString(), Name));
} public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]任务监听,name:{1}|任务执行完成。"
, DateTime.Now.ToLongTimeString(), Name));
}
#endregion #region ITriggerListener
public async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]触发器监听,name:{1}|触发器触发成功。"
, DateTime.Now.ToLongTimeString(), trigger.Key.Name));
} public async Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]触发器监听,name:{1}|触发器开始触发。"
, DateTime.Now.ToLongTimeString(), trigger.Key.Name));
} public async Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]触发器监听,name:{1}|触发器触发失败。"
, DateTime.Now.ToLongTimeString(), trigger.Key.Name));
} public async Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken))
{
await Console.Error.WriteLineAsync(string.Format("[{0}]触发器监听,name:{1}|可以阻止该任务执行,这里不设阻拦。"
, DateTime.Now.ToLongTimeString(), trigger.Key.Name));
// False 时,不阻止该任务。True 阻止执行
return false;
}
#endregion
}
}
}

实验效果

如截图所示,这里只执行一次。注意观察:触发器监听优先级 > 任务监听优先级

image

上篇

上篇:作业调度框架Quartz.NET-01-快速入门

Thanks

Quartz.NET

张善友的博客

作业调度框架Quartz.NET-现学现用-02-任务监听的更多相关文章

  1. 作业调度框架Quartz.NET-现学现用-01-快速入门

    原文:作业调度框架Quartz.NET-现学现用-01-快速入门 前言 你需要应用执行一个任务吗?这个任务每天或每周星期二晚上11:30,或许仅仅每个月的最后一天执行.一个自动执行而无须干预的任务在执 ...

  2. 作业调度框架Quartz.NET-现学现用-02-任务监听 - 简书

    原文:作业调度框架Quartz.NET-现学现用-02-任务监听 - 简书 前言 任务调度系统并不是完美的,它会出现任务执行失败的情况.如果你需要处理任务失败后的逻辑,希望这篇笔记可以为你提供些帮助. ...

  3. 作业调度框架Quartz.NET-现学现用-01-快速入门 - 简书

    原文:作业调度框架Quartz.NET-现学现用-01-快速入门 - 简书 前言 你需要应用执行一个任务吗?这个任务每天或每周星期二晚上11:30,或许仅仅每个月的最后一天执行.一个自动执行而无须干预 ...

  4. .NET开源作业调度框架(Quartz.NET和FluentScheduler)实战项目演练

    一.课程介绍 明人不说暗话,跟着阿笨一起玩NET .本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享 ...

  5. 作业调度框架Quartz.NET | 大专栏

    原文:作业调度框架Quartz.NET | 大专栏 作业调度框架Quartz.NET 发表于 2019-09-28 |  分类于 前端 |  没有评论 前言 任务调度系统并不是完美的,它会出现任务执行 ...

  6. 作业调度框架 Quartz.NET 2.0 StepByStep

    注:目前网上诸多介绍Quartz.net的文章,甚至Quartz.net官网上的Tutorial都是1.0版本的,而这个项目在2.0版本对项目进行了比较大规模的修改,使得原有的很多例子都不能运行,故写 ...

  7. .Net平台开源作业调度框架Quartz.Net

    Quartz.NET介绍: Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中. ...

  8. (转).Net平台开源作业调度框架Quartz.Net

    Quartz.NET介绍: Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中. ...

  9. java作业调度框架Quartz

    在软件开发中,很多时候需要在特定时间的时间执行某些操作,比如每天的凌晨三点.每周的周日.每个月的15号,Apache Quartz就是一个开源的作业调度框架,可以让计划的程序任务一个预定义的日期和时间 ...

随机推荐

  1. SpringMVC自定义类型转换器

    SpringMVC 自定义类型转换器  我们在使用SpringMVC时,常常需要把表单中的参数映射到我们对象的属性中,我们可以在默认的spring-servlet.xml加上如下的配置即可做到普通数据 ...

  2. node.js之客户端发起https和http请求

    应用场景:1.VsCode插件开发(主要针对以javascript为主的vscode插件);2.使用Node.js开发的客户端程序 Node.js之http请求(客户端) 代码示例如下: var ht ...

  3. 刷题记录:[网鼎杯]Fakebook

    目录 刷题记录:[网鼎杯]Fakebook 一.涉及知识点 1.敏感文件泄露 2.sql注入 二.解题方法 刷题记录:[网鼎杯]Fakebook 题目复现链接:https://buuoj.cn/cha ...

  4. cnetos7 搭建wordpress(apache+php+mariadb)

    .安装apache.php.php库 yum -y install httpd php php-mbstring php-pear 2.修改php配置文件地区 vim /etc/php.ini 在87 ...

  5. 大div套多个小div,怎样设置外div的高度自适应?

    在最后一个div 后面加上 overflow:hidden;如下: <div style="width:580px; height:auto; margin:0 auto; <d ...

  6. SnowFlake分布式ID生成及反解析

    概述 分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种,SnowFlake算法生成id的结果是一个64bit大小的整数,它的结构如下图: 1位,不用.二进制中最高位为 ...

  7. libusb: android上集成libusb库

    1. 下载libusb库. 可以到libusb库的官网(https://libusb.info/)或者是其官方的github仓库(https://github.com/libusb/libusb/re ...

  8. 《精通CSS第3版》(5)漂亮的盒子

  9. 判断命令test

    判断命令test一般用于脚本当中,可以简写为中括号[ ].其会对跟随的条件进行判断,一般可以分为数值判断.字符串判断和文件判断.语法格式为test [判断条件]或[ 判断条件 ],注意中括号[ ]与判 ...

  10. ubuntu中cmake版本升级

    在网上下载一个项目,编译提示版本太低 CMake Error at CMakeLists.txt: (cmake_minimum_required): CMake 编译方式安装(需要openssl) ...