11

Quartz.Net 主要概念介绍和吐槽 - 莱布尼茨

 2 years ago
source link: https://www.cnblogs.com/newton/p/17073896.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我们经常遇到需要定时执行某些任务的情况,比如清理缓存、异步结果轮询等,如果不打算造轮子,那么选择一款合适的定时任务组件就很关键了。所幸,.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 misfire详解


Recommend

  • 9

    用简单的物理方法证明牛顿莱布尼茨公式 发表于 2020-12-25...

  • 9
    • sht2019.cn 3 years ago
    • Cache

    莱布尼茨笔记

    Gottfried Wilhelm Leibniz - Wikipedia Pierre Gassendi - Wikipedia

  • 7

    15种主要编程语言介绍及应用场合 俗话说的好,风水轮流转。一直处于食物链底端的程序员终于迎来了逆袭的机会!时薪300美元以上、跻身高层...

  • 7
    • sht2019.cn 3 years ago
    • Cache

    莱布尼茨笔记II

    Gottfried Wilhelm Leibniz - Wikipedia Ralph Cudworth - Wikipedia

  • 10
    • example.com 3 years ago
    • Cache

    Unix I/O 主要模型介绍

    Example Domain This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.

  • 4

    马克·尼茨伯格:中国在人工智能产业发展中有哪些优势? 当下,人工智能正在掀起一场无所不在且可能持续长达30年的发展浪潮。 尽管中美两国存在文化、政治和经济差异,但相同的是学术界和产业界的密切互动,使得两个国家的人工智能产业发展飞...

  • 5

    iPhone 15 Pro四色概念图曝光,网友疯狂吐槽-蓝鲸财经 1 00:44 1万投入A股,2021年极限赚多少? ...

  • 6

    莱布尼茨对通用思想语言的探索 计算机科学的现代史可以说是从有史以来最著名的数学家之一戈特弗里德·莱布尼茨 ( Gottfried Leibniz ) 开始的。...

  • 5
    • holydogs.github.io 2 years ago
    • Cache

    【quartz】集群运行与相关表介绍

    qrtz_blob_triggers(以Blob 类型存储的触发器。)—Trigger作为Blob类型存储–(用于Quartz用户用JDBC创建他们自己定制的 Trigger类型,JobStore并不知道如何存储实例的时候)

  • 2

    笔者个人理解:gitlab-runner 安装后就是一个监听状态的 runner,而通过 gitlab-runner register 注册的“实例”其实只是预定义的配置节,当消息抵达后,gitlab-runner 根据消息内容选择相应的配置节启动执行线程。为了方便阐述和理解,本文也将每个

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK