Quartz.Net 官方教程 Best Practices
最佳实践
JobDataMap
建议只存储基本数据(含String),避免序列化问题
作业执行期间,JobDetail和Trgger的底层共用一个JobDataMap 实例,因此Trigger的数据会覆盖Job中相同key的值。
每个独立触发器的JobDataMap 是独立的
在作业执行期间,建议使用MergedJobDataMap去检索key
// 不建议
var badMethod = context.JobDetail.JobDataMap.GetString("a-value");
var alsoBadMethod = context.Trigger.JobDataMap.GetString("a-value");
// 建议
var goodMethod = context.MergedJobDataMap.GetString("a-value");
Job
为统一作业的名称和群组,建议在IJob实现时就声明一个静态JobKey,便于触发器赋值使用
public class SomeJob : IJob
{
// 定义当前作业的名称和群组
public static readonly JobKey Key = new JobKey("job-name", "group-name");
public Task Execute(IJobExecutionContext context) { /* elided */ }
}
// 创建触发器
public async Task DoSomething(IScheduler schedule, CancellationToken ct)
{
var trigger = TriggerBuilder.Create()
.WithIdentity("a-trigger", "a-group")
.ForJob(SomeJob.Key)
.StartNow()
.Build();
await schedule.ScheduleJob(trigger, ct)
}
// 设置当前作业的触发器时
public async Task DoSomething(IScheduler schedule, CancellationToken ct)
{
await schedule.TriggerJob(SomeJob.Key, ct)
}
Trigger
使用TriggerUtils进行触发器时间上的操作
根据触发器获得执行时间列表
static IReadOnlyList ComputeFireTimes(IOperableTrigger trigg, ICalendar? cal, int numTimes)
// 设置时间
DateTimeOffset startCalendar = DateBuilder.DateOf(9, 30, 17, 1, 1, 2023);
// 设置日期的触发器,间隔90天执行一次,从2023-01-01 17:30:09开始
var dailyTrigger = new CalendarIntervalTriggerImpl
{
StartTimeUtc = startCalendar,
RepeatIntervalUnit = IntervalUnit.Day,
RepeatInterval = 90 // every ninety days
};
// 2023年1月1日加上360天 4*90 四个90天的循环
DateTimeOffset targetCalendar = startCalendar.AddDays(360);
// 获得从0开始的6次循环(0-5)
var fireTimes = TriggerUtils.ComputeFireTimes(dailyTrigger, null, 6);
// 获得第五次的循环日期,2023-01-01 17:30:09当天也会执行一次
DateTimeOffset fifthTime = fireTimes[4]; // get the fifth fire time
// 两次获得的日期相同
Assert.AreEqual(targetCalendar, fifthTime, "Day increment result not as expected.");
获得触发器最后一次执行的时间
static DateTimeOffset? ComputeEndTimeToAllowParticularNumberOfFirings(IOperableTrigger trigger, ICalendar? calendar, int numberOfTimes)
// 设置时间
DateTimeOffset startCalendar = DateBuilder.DateOf(9, 30, 17, 1, 1, 2023);
// 设置日期的触发器,间隔90天执行一次,从2023-01-01 17:30:09开始
var dailyTrigger = new CalendarIntervalTriggerImpl
{
StartTimeUtc = startCalendar,
RepeatIntervalUnit = IntervalUnit.Day,
RepeatInterval = 90 // every ninety days
};
// 2023年1月1日加上360天 4*90 四个90天的循环
DateTimeOffset targetCalendar = startCalendar.AddDays(360);
// 获得从0开始的4次循环(0-3),然后返回第四次执行的时间
var endFireTimes = TriggerUtils.ComputeFireTimes(dailyTrigger, null, 4);
// 两次获得的日期相同
Assert.AreEqual(targetCalendar, fifthTime, "Day increment result not as expected.");
在两个日期之间触发器执行的时间列表
static IReadOnlyList ComputeFireTimesBetween(IOperableTrigger trigg, ICalendar? cal, DateTimeOffset from, DateTimeOffset to)
// 设置触发器
var trigger = (IOperableTrigger) TriggerBuilder.Create()
.WithDailyTimeIntervalSchedule(x => x
.InTimeZone(TZConvert.GetTimeZoneInfo("GTB Standard Time"))
// 每天从0点开始
.StartingDailyAt(new TimeOfDay(0, 0, 0))
// 跳过21点,第二次循环跳过了20和21点
.EndingDailyAt(new TimeOfDay(22, 0, 0))
// 15分钟循环一次
.WithInterval(15, IntervalUnit.Minute)
// 触发失效什么也不做
.WithMisfireHandlingInstructionDoNothing()
)
.Build();
var from = new DateTimeOffset(2023, 1, 31, 0, 0, 0, TimeSpan.Zero);
var to = new DateTimeOffset(2023, 2, 2, 0, 0, 0, TimeSpan.Zero);
//理论上会执行 ((23个小时+22个小时)*60分钟)/(15分钟/次) - 1次 = 179次
var times = TriggerUtils.ComputeFireTimesBetween(trigger, null, from, to);
// 小于200次
Assert.That(times.Count, Is.LessThan(200));
ADO.NET JobStore
- 使用Quartz.NET的API写入数据库,不要直接操作数据库表
- 死锁
- 触发器中的作业未被正确执行
- 集群之间的问题
- 非集群与集群不能共用一个数据库
- 数据源连接大小
- 建议将数据源最大连接大小配置为至少为线程池中的工作线程数加上三
- 如果使用Api则需要额外的连接
Daylight Savings Time
夏令时-中国在执行了6年就取消了,因此该最佳实现目前不适用于无夏令时的地区。
因为SimpleTriggers为精确到毫秒,因此不受夏令时的影响;CronTriggers在转换的时候会受到夏令时的影响,可能会多触发一次;CalenderIntervalTrigger也会受影响,会导致偏移一小时的误差。
Jobs
- 长时间运行的作业会阻止其他线程运行(例如已运行作业数量与线程池数量相等)
- 不建议在作业中使用Thread.Sleep(),因为他会让线程一直被占用,建议在使用Sleep的位置重新安排自身或者其他作业来替代等待(通常等待是因为条件不为true,因此可以将该判断作为作业执行,周期短)
- 因为作业是周期性的,因此当作业异常时会一直触发异常,此时异常过多会导致应用程序不稳定。建议在catch处解决异常或重新开启新的作业来消解异常的发生。
Listener
- 不建议监听中执行大量工作,因为作业更合适做这些工作,监听只是监听。
- 同Jobs的异常处理,异常多了容易崩溃。
对外调用
- 不建议对外暴露,对于本机过于危险(例如NativeJob和SendEmailJob都可以用于恶意的目的)
Quartz.Net 官方教程 Best Practices的更多相关文章
- Unity性能优化(3)-官方教程Optimizing garbage collection in Unity games翻译
本文是Unity官方教程,性能优化系列的第三篇<Optimizing garbage collection in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
- Unity性能优化(4)-官方教程Optimizing graphics rendering in Unity games翻译
本文是Unity官方教程,性能优化系列的第四篇<Optimizing graphics rendering in Unity games>的翻译. 相关文章: Unity性能优化(1)-官 ...
- Quartz.net官方开发指南系列篇
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性而不牺牲 ...
- Unity性能优化(2)-官方教程Diagnosing performance problems using the Profiler window翻译
本文是Unity官方教程,性能优化系列的第二篇<Diagnosing performance problems using the Profiler window>的简单翻译. 相关文章: ...
- Unity性能优化(1)-官方教程The Profiler window翻译
本文是Unity官方教程,性能优化系列的第一篇<The Profiler window>的简单翻译. 相关文章: Unity性能优化(1)-官方教程The Profiler window翻 ...
- jeecg表单页面控件权限设置(请先看官方教程,如果能看懂就不用看这里了)
只是把看了官方教程后,觉得不清楚地方补充说明一下: 1. 2. 3. 4.用"jeecgDemoController.do?addorupdate"这个路径测试,不出意外现在应该可 ...
- [转]Google Guava官方教程(中文版)
Google Guava官方教程(中文版) http://ifeve.com/google-guava/
- Google Guava官方教程(中文版)
Google Guava官方教程(中文版) 原文链接 译文链接 译者: 沈义扬,罗立树,何一昕,武祖 校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库, ...
- OpenGL官方教程——着色器语言概述
OpenGL官方教程——着色器语言概述 OpenGL官方教程——着色器语言概述 可编程图形硬件管线(流水线) 可编程顶点处理器 可编程几何处理器 可编程片元处理器 语言 可编程图形硬件管线(流水线) ...
- [苏飞开发助手V1.0测试版]官方教程与升级报告
[苏飞开发助手V1.0测试版]官方教程与升级报告导读部分----------------------------------------------------------------- ...
随机推荐
- 如何解读Linux Kernel OOPS信息
OOPS信息解读 root@firefly:~/mnt/module# insmod oops_module.ko [ 867.140514] Unable to handle kernel NULL ...
- 京东云开发者|关于“React 和 Vue 该用哪个”我真的栓Q
一.前言:我全都要 面对当今前端界两座大山一样的主流框架,React和Vue,相信很多小伙伴都或多或少都产生过这样疑问,而这样的问题也往往很让人头疼和犹豫不决: 业务场景中是不是团队用什么我就用什么? ...
- 最长不下降子序列(线段树优化dp)
最长不下降子序列 题目大意: 给定一个长度为 N 的整数序列:A\(_{1}\),A\(_{2}\),⋅⋅⋅,A\(_{N}\). 现在你有一次机会,将其中连续的 K 个数修改成任意一个相同值. 请你 ...
- 嵌入式-C语言基础:字符串结束标识符
#include<stdio.h> int main() { char cdata[]={'h','e','l','l','o'}; char cdata2[]="hello&q ...
- 万字干货_JDK动态代理及其源码解析 拿捏了
目录 代理模式 静态代理 静态代理和动态代理的区别?什么是静态.动态? 静态代理的使用步骤 示例 静态代理的缺陷 解决静态代理的缺陷的思路 JDK动态代理 JDK 动态代理类使用步骤 示例 底层原理 ...
- 带你了解S12直播中的“黑科技”
摘要:让精彩更流畅.让较量更清晰.让参与更沉浸.让体验更有趣,幕后的舞台,从来都是技术的战场,S12背后的名场面同样场场高能. 本文分享自华为云社区<用硬核方式打开S12名场面>,作者:华 ...
- Bigkey问题的解决思路与方式探索
作者:vivo 互联网数据库团队- Du Ting 在Redis运维过程中,由于Bigkey 的存在,会影响业务程序的响应速度,严重的还会造成可用性损失,DBA也一直和业务开发方强调 Bigkey 的 ...
- Spring Security(4)
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 前面的方法中,除了login()方法能成功,另外两个都失败,并不是因为代码问题,而是Spring Security默认是通过Web页面来实现页面 ...
- 卸载virtualbox中linux虚拟机的增强工具
报错信息 vboxclient:the virtualbox kernel service is not running 前言 我由virtualbox换到vmware 遇到了这个问题,很烦每次都通知 ...
- win7修改开机动画
开机动画的修改 首先win7的过场动画是存在于C:\Windows\System32\bootres.dll ,而修改过程动画就需要修改这个dll,我不会改,所以只能用工具美化大师,软媒魔方里面的一个 ...