Quartz.Net 主要概念介绍和吐槽
我们经常遇到需要定时执行某些任务的情况,比如清理缓存、异步结果轮询等,如果不打算造轮子,那么选择一款合适的定时任务组件就很关键了。所幸,.Net 世界中的选项并不多:)
选型
主要有以下四款:
Quartz.Net:移植自 Java 生态的Quartz,久经考验、成熟稳重,只是个人感觉有点过度设计,初次接触容易让人困惑;Coravel:提供任务调度,缓存,排队,邮件,事件广播等功能,全面但不专一;Hangfire:最大的特点是内置控制面板。分为社区版和商用版。github 上,这四款组件它的点赞数最多,可见其收欢迎程度。不过它更像一个定时任务管理解决方案,所涵盖的功能除任务本身,还涉及到账户管理、图表管理、告警系统等;FluentScheduler:似乎是这四款中最易上手的,但是已经有段时间没更新了。
稳妥起见,项目前期建议选择坑少、专注、轻量、社区较为活跃的组件 Quartz.Net,再择机使用 Hangfire 打造一个任务管理中心。
如前所述,Quartz.Net 有过度设计的嫌疑,2.x 版本时期配置方式的杂乱可见一斑。虽然现在已经迭代到 3.x,一些概念还是需要花心思理解下。
主要概念
我们围绕下面这个代码片段展开:
var schedulerFactory = builder.Services.GetRequiredService<ISchedulerFactory>();
var scheduler = await schedulerFactory.GetScheduler();
// define the job and tie it to our HelloJob class
var job = JobBuilder.Create<HelloJob>()
.WithIdentity("myJob", "group1")
.UsingJobData("way", "email")
.Build();
// Trigger the job to run now, and then every 40 seconds
var trigger = TriggerBuilder.Create()
.WithIdentity("myTrigger", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(40)
.RepeatForever())
.Build();
await scheduler.ScheduleJob(job, trigger);
Jobs and Triggers
Quartz.Net 将任务业务逻辑(Jobs)和任务执行时间计划(Triggers)做了分离。官方的解释是两者可以独立管理,还可以多个 Trigger 触发同一个 Job;有没有必要见仁见智。
Job 和 Trigger 还有group的概念,比如多个模块都有各自清理缓存的任务,可以将这些任务划分为同一个组。但是在实操过程中,group 除了语义上的指示,似乎并没有直接的其它作用;也许它可以用于业务端的扩展,不过私以为组件不应将可能的业务需求作为自己的设计点,且业务扩展不应依赖某个具体组件。
JobDetail
上述代码中变量 job 的类型并非IJob,而是IJobDetail,也就是说,Quartz.Net 调度维持的是 IJobDetail 实例,而 Job 实例,是在每次任务执行的时间点实例化的,执行完就销毁,实例状态并不能延续,需要借助 IJobDetail 实例存取每次执行后更新的状态。
JobDataMap
Job 实例状态保存在 JobDataMap 中,构造 JobDetail 对象时使用 .UsingJobData(key, value) 定义键值对。Trigger 也有 JobDataMap,是为上面提到的———多个 Trigger 触发同一个 Job——这种情况设计的。
使用方式如下:
public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
JobKey key = context.JobDetail.Key;
// 可使用 context.MergedJobDataMap 同时获取 Trigger 提供的键值
JobDataMap dataMap = context.JobDetail.JobDataMap;
string way = dataMap.GetString("way");
await Console.Error.WriteLineAsync("Instance " + key + " of HelloJob is send by: " + way);
}
}
另外要注意的是,用来修饰 Job 类的特性DisallowConcurrentExecution,其实约束的是 JobDetail,即对于 JobDetail-A,同一时间,只能有一个 Job 使用它。也就是说,可以同时激活多个 HelloJob 对象,只要它们关联的 JobDetail 不同即可(当然了,实际我们也只能操作多个不同的 JobDetail 去激活对应的 Job)。
关于 JobDetail 的解释,官方文档写得过于复杂,其实它的目的就是为了解决 Job 实例并非单例的问题,那么作者为什么不干脆将 Job 实例单例化呢?根本没必要创造一个多余的 JobDetail 的概念,令人费解。如果是因为并发考量,那么应该从 Job 定义入手,加入多线程支持。
如果项目中使用了 IOC,那么我们可以选择不使用 JobDataMap,而是将实例状态保存在自定义对象中,在每次实例化 Job 对象时注入。
Misfire 处理方案
当一个 Job 在规定时间点没有被触发执行(比如线程池里面没有可用的线程、Job 被暂停等),且超时时间超过 misfireThreshold 配置的值(默认为60秒),则作业会被调度程序认为Misfire。
当系统恢复后(有空闲线程、Job 被恢复等),调度程序会根据配置的 Misfire 策略处理已错过的那些触发点。
参考资料
Quartz.Net 主要概念介绍和吐槽的更多相关文章
- 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之集群概念介绍(一)
集群概念介绍(一)) 白宁超 2015年7月16日 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习 ...
- Linux LVM硬盘管理之一:概念介绍
一.LVM概念介绍: LVM是 Logical Volume Manager(逻辑卷管理)的简写,它由Heinz Mauelshagen在Linux 2.4内核上实现.LVM将一个或多个硬盘的分区在逻 ...
- Java SE/ME/EE的概念介绍
转自 Java SE/ME/EE的概念介绍 多数编程语言都有预选编译好的类库以支持各种特定的功能,在Java中,类库以包(package)的形式提供,不同版本的Java提供不同的包,以面向特定的应用. ...
- rocketMq概念介绍
rocketMq官网 http://rocketmq.apache.org/ rocketMq逻辑概念介绍 rocketMq逻辑图 备注: 改图片分享自李占卫的网上家园 说明: 在rocketM ...
- java 并发多线程 锁的分类概念介绍 多线程下篇(二)
接下来对锁的概念再次进行深入的介绍 之前反复的提到锁,通常的理解就是,锁---互斥---同步---阻塞 其实这是常用的独占锁(排它锁)的概念,也是一种简单粗暴的解决方案 抗战电影中,经常出现为了阻止日 ...
- Airflow Python工作流引擎的重要概念介绍
Airflow Python工作流引擎的重要概念介绍 - watermelonbig的专栏 - CSDN博客https://blog.csdn.net/watermelonbig/article/de ...
- spring batch (一) 常见的基本的概念介绍
SpringBatch的基本概念介绍 内容来自<Spring Batch 批处理框架>,作者:刘相. 一.配置文件 在项目中使用spring batch 需要在配置文件中声明: 事务管理器 ...
- helm-chart-1-简单概念介绍-仓库搭建-在rancher上的使用
简单的概念介绍: Chart是helm管理的应用的打包格式,一个chart对应一个或一套应用.内部是一系列的yaml描述文件,以为为yaml 服务的文件. 三个部分,helm .tiller.repo ...
- Netty重要概念介绍
Netty重要概念介绍 Bootstrap Netty应用程序通过设置bootstrap(引导)类开始,该类提供了一个用于网络成配置的容器. 一种是用于客户端的Bootstrap 一种是用于服务端的S ...
- 《AngularJS深度剖析与最佳实践》笔记: 第二章 概念介绍
第二章 概念介绍 2.1 什么是UI? 用户界面包括内容(静态信息+动态信息), 外观, 交互. 在前端技术栈中分别由HTML, CSS和JS负责. 进一步抽象, 分别对应于MVC三个主要部分: Mo ...
随机推荐
- 关于sublime-build的配置详解
前言 sublime-build 可以做很多自定义的构建命令,然后用其执行代码,十分方便! 开始 这里我就简单的用python 的配置来详细说明各个配置项目的作用 { "shell_cmd& ...
- Day29:StringBuilder详解
StringBuilder 1.1 StringBuilder概述 我们先对普通的String字符串对象建立进行内存分析: public class Demo{ public static void ...
- ATM项目
ATM项目实战 项目需求分析: 1.注册(密码要加密) 2.登陆 3.查看余额 4.提现(可自定手续费) 5.还款 6.转账 7.查看流水 8.添加购物车功能 (商品可配置) 9.查看购物车功能 10 ...
- 用openpyxl创建工作簿和工作表
import osimport openpyxl #设置默认路径os.chdir(r'D:/openpyxl/') #创建工作簿变量 wb = openpyxl.Workbook() #创建工作表变量 ...
- forms组件源码剖析
一:forms组件源码剖析 1.forms组件源码切入点: 1.0 form_obj.is_valid() 2.0 def is_valid(self): """ Ret ...
- 【JVM故障问题排查心得】「内存诊断系列」Docker容器经常被kill掉,k8s中该节点的pod也被驱赶,怎么分析?
背景介绍 最近的docker容器经常被kill掉,k8s中该节点的pod也被驱赶. 我有一个在主机中运行的Docker容器(也有在同一主机中运行的其他容器).该Docker容器中的应用程序将会计算数据 ...
- java中的instanceof方法
本文主要讲述java中的instanceof()方法. 示例代码如下: public class InstanceTest { public static void main(String[] arg ...
- java中的递归机制
本文主要讲述java中的递归机制. 示例1,递归代码如下: public class Recursion01 { public static void main(String[] args) { T ...
- JavaScript:this指针
this指针,存储的是一个内存地址,如同变量一样,指向一块内存区域: 而这个内存区域,保存的就是一个对象的数据,那么这个对象是什么呢? 通常来说,this指针,主要是用在方法(函数)中,用来指向调用方 ...
- JavaScript:七大基础数据类型:布尔值boolean、空null、未定义undefined
布尔值boolean 没什么好说的,同其他编程语言一样,就两个值:true 和 false: 空null JS的null,和Java等编程语言的概念不一样,它不是一个"不存在的对象" ...