Quartz.NET 的任务调度管理工具
[更新] 基于Quartz.NET 的任务调度管理工具
更新列表:
- 任务参数可视化.
- 立即中断正在执行的任务.
- 每个任务独立的应用程序域
上一版参见:
基于Quqrtz.NET 做的任务调度管理工具
界面具体变化如下:
任务参数可视化
如上图所示, 在管理任务的界面上就可以知道这个任务需哪些参数/类型 及 参数的说明.
实现方式, 在 Job 上添加 特性 : ParameterTypeAttribute

1 namespace JobA {
2 [ParameterType(typeof(Parameter))]
3 public class Job : IJob {
4
5 public static ILog Log = LogManager.GetLogger(typeof(Job));
6 public void Execute(IJobExecutionContext context) {
7 var dataMap = context.JobDetail.JobDataMap;
8 //if (dataMap.ContainsKey("int")) {
9 // var pInt = dataMap.GetIntValue("int");
10 // Console.WriteLine("1 JobA Parameter {0}", pInt);
11 //} else {
12 // Log.Error("缺少参数 int, 未执行");
13 // throw new JobExecutionException("缺少参数");
14 //}
15
16 var p = dataMap.Parse<Parameter>();
17 Console.WriteLine("{0}\t{1}\t{2}\t{3}", p.PDateTime, p.PDecimal, p.PInt, p.PNullableInt);
18
19
20 Thread.Sleep(TimeSpan.FromMinutes(3));
21 }
22 }
23 }

取参数直接调用 dataMap.Parse<Parameter>() 就行了.
Parse 方法在: QM.Common. DatamapParser 中定义.
相比原始的从 DataMap 中用 key / value 方法取参数, 这种处理方式的好处不言而喻.
但是也有缺点, DataMap 支持任何可序列化的类型,
而用这种方法只支持
string, decimal, long, int, single, double, DateTime, DateTimeOffset, TimeSpan , bool, char 这些类型. (没有做更深一步的处理, 有兴趣的,可以尝试自己去实现.)
每个任务独立的应用程序域
试想一下插件式开发, 如果你做的插件需要N个第三方DLL, 而这些DLL并没有引用到主项目上, 怎么办呢? 一堆的 FileLoadException, FileNotFoundException 等错误, 想想都头疼.
如果你开发的插件想拥有自己的配置文件, 又该怎么办呢? 自己实现一个配置文件读取解析? ini ? xml ? 头疼吧.
针对上面的问题, 在这里的最佳解决办法是 : 独立的应用程序域.
这个要从 IScheduler.JobFactory 说起.
在QM.Server.QMServer 的构造方法中, 指定 Schedule.JobFactory 为 IsolatedJobFactory
IsolatedJobFactory 的定义:

1 public class IsolatedJobFactory : IJobFactory {
2
3 public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) {
4 return NewJob(bundle.JobDetail.JobType);
5 }
6
7 private IJob NewJob(Type jobType) {
8 return new IsolatedJob(jobType);
9 }
10
11 public void ReturnJob(IJob job) {
12 IDisposable disposable = job as IDisposable;
13 if (disposable != null) {
14 disposable.Dispose();
15 }
16 }
17 }

从 NewJob 方法上可以看出, 实例出来的 Job 并不是最终要执行的 Job, 而是 IsolatedJob 的实例, 它类似中间人的身份.
IsolatedJob 实现了 IInterruptableJob 接口, 为中断执行中的任务埋下伏笔.
在 IsolatedJob 的构造方法中, 通过 IsolateDomainLoader 新建一个应用程序域:
IsolatedDomainLoader 的构造函数:

1 public IsolateDomainLoader(string path, string configFileName = "") {
2 AppDomainSetup setup = new AppDomainSetup();
3 setup.ApplicationName = "IsolateDomainLoader";
4 setup.ApplicationBase = path;
5 setup.DynamicBase = path;
6 setup.PrivateBinPath = path;
7 setup.CachePath = setup.ApplicationBase;
8 setup.ShadowCopyFiles = "true";
9 setup.ShadowCopyDirectories = setup.ApplicationBase;
10 if (!string.IsNullOrWhiteSpace(configFileName)) {
11 setup.ConfigurationFile = configFileName;
12 setup.ConfigurationFile = Path.Combine(path, configFileName);
13 }
14 this.Domain = AppDomain.CreateDomain("ApplicationLoaderDomain", null, setup);
15 }

参数 path 即最终要执行的 job 所在的 dll 的路径.
configFileName 即独立的配置文件名称.
这样一来, 一个 job 一个文件夹, 文件夹内放置这个 job 相关的DLL和配置文件, 和主程序完全隔离开来.
上面说 IsolatedJob 是个中间人, 这里解释一下:
1, IsolatedJobFactory 的 NewJob 方法返回的是 IsolatedJob 的实例, 而不是最终要执行的 Job.
2, 在 IsolatedJob 中, 会通过独立的应用程序域 实例一个最终要执行的 Job 的远程对象(通过 RemoteObject).
3, 当中间人的 Execute 方法被调用时, 会调用远程 Job 对象的 Execute 方法.
4, Interrupt 方法同理.
远程对象续约
因为独立的应用程序域用到了远程对象: MarshalByRefObject, 因此涉及到了远程对象的租约过期及续租的问题.
远程对象的租约默认为 5 分钟, 可以重写 InitializeLifetimeService 方法来修改租约的有效期. 但是一个 Job 不确定要执行多长时间, 修改租约有效期不是很合适, 所以这里是通过续约的方式来处理租约过期的问题.
本人对租约了解不多, 不多嘴.感兴趣的话,可参见源码:
QM.RemoteLoader.RemoteObjectSponsor 类
和 QM.RemoteLoader.IsolateDomainLoader类的 GetObject 方法.
立即中断正在执行的任务
这个命题是有条件的, 即: 任务必须实现: IInterruptableJob 接口.
一般一个任务要执行很长时间, 如果不给个中断的接口, 那就只能关闭服务或等任务执行完毕了.
实现了这个接口,在配合 CancellationToken.ThrowIfCancellationRequested 方法就可以中断当前执行的任务了(别告诉我,你的任务是单线程的).
卸载域
任务执行完成后, 会将关联的 IsolatedJob对象释放, 在 IsolatedJob 的 Dispose 方法中,会把IsolateDomainLoader 对象释放,IsolateDomainLoader 释放的时候, 会把关联的子应用程序域卸载.
所以, 如果如果你的任务是多线程的, 请在线程远行完之前, 进行阻塞.
自定义Job的基类
目前, 如果自定义的 Job 的基类在第三方DLL中, 而且第三方DLL未引用到QM.Server 项目中, 并且不在 QM.Server\Jobs 目录下, 会报:
未能加载文件或程序集 XXX 或它的某一个依赖项。系统找不到指定的文件。
解决办法有两种:
1, 将缺少的DLL放到Jobs 目录下.
2, 将缺少的DLL添加引用到 QM.Server 中.
注意, 该限制只针对 Job 的基类. 除基类使用外的第三方DLL不需要这样做, 在JOB上引用就是了.
放上一段不用的, 可终止的 任务示例代码 给你做参考
最后, 源码下载
https://github.com/gruan01/QM
Quartz.NET 的任务调度管理工具的更多相关文章
- 基于Quqrtz.NET 做的任务调度管理工具
基于Quqrtz.NET 做的任务调度管理工具 国庆前,需求让我看了一下任务调度的数据表设计.和之前一样,有100多个字段,p1 ~ p100, 我说这是干嘛啊!按这写,写死去了! 然后在网上搜了一下 ...
- 使用Quartz.NET进行任务调度管理
1.Quartz.NET 介绍 Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用 ...
- quartz 定时任务调度管理器
本项目使用的是spring-quartz 以下配置可以开启多个已知定时任务 <?xml version="1.0" encoding="UTF-8"?&g ...
- Docker集群管理工具 - Kubernetes 部署记录 (运维小结)
一. Kubernetes 介绍 Kubernetes是一个全新的基于容器技术的分布式架构领先方案, 它是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,Kubernete ...
- 基于KVM、Xen、OpenVZ等虚拟化技术的WEB在线管理工具
1.Proxmox proxmox是一个开源的虚拟化管理平台,支持集群管理和HA.在存储方面,proxmox除了支持常用的lvm,nfs,iscsi,还支持集群存储glusterfs和ceph,这也是 ...
- Linux服务管理(Ubuntu服务管理工具sysv-rc-conf)(转)
Linux运行级别 Linux系统任何时候都运行在一个指定的运行级上,并且不同的运行级的程序和服务都不同,所要完成的工作和要达到的目的都不同,系统可以在这些运行级之间进行切换,以完成不同的工作. 运行 ...
- RDIFramework.NET框架基于Quartz.Net实现任务调度详解及效果展示
在上一篇Quartz.Net实现作业定时调度详解,我们通过实例代码详细讲解与演示了基于Quartz.NET开发的详细方法.本篇我们主要讲述基于RDIFramework.NET框架整合Quartz.NE ...
- Postman - 功能强大的 API 接口请求调试和管理工具
Postman 是一款功能强大的的 Chrome 应用,可以便捷的调试接口.前端开发人员在开发或者调试 Web 程序的时候是需要一些方法来跟踪网页请求的,用户可以使用一些网络的监视工具比如著名的 Fi ...
- JDK 中的证书生成和管理工具 keytool
参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...
随机推荐
- centos 彻底删除nodejs默认的安装文件
1> yum remove nodejs npm -y 2> cd /usr/local/lib 移除所有 node 和 node_modules目录 cd /usr/local/in ...
- Lock_sga 和 pre_page_sga 参数详解
Lock_sga 和 pre_page_sga 参数详解 Lock_sga 和pre_page_sga,是两个平时用的不算太多的参数,但是这两个参数平时在优化的时候可能给你带来比较乐观的 ...
- JAVA 跑马灯文字效果
JAVA跑马灯文字效果的实现: 1. 首先创建一个继承JFrame类的HorseRaceLightTextFrame窗体类,代码如下: package com.example.horseracelig ...
- 在SQL Server Management Studio中可以运行作业但是用T-SQL运行则失败
原文:在SQL Server Management Studio中可以运行作业但是用T-SQL运行则失败 问题: 在SQL Server Management Studio中可以运行作业但是用T-SQ ...
- HTML5 transform三维立方体(随着旋转的效果)
为了得到更好的把握transform精华.因此,我们决定完成三维立方体模型,可以实现360无死三维旋转作用. 但旋转更难推断每侧视图的序列.然而,完美的解决方案,我希望有人能回答. 源代码直接贡献的朋 ...
- ContentProvider总结(Android)
ContentProvider 1.适用场景 1) ContentProvider为存储和读取数据提供了统一的接口 2) 使用ContentProvider,应用程序能够实现数据共享 3) andro ...
- Linux内核分析(五)----字符设备驱动实现
原文:Linux内核分析(五)----字符设备驱动实现 Linux内核分析(五) 昨天我们对linux内核的子系统进行简单的认识,今天我们正式进入驱动的开发,我们今后的学习为了避免大家没有硬件的缺陷, ...
- j2se--Socket沟通
第一次接触Socket课程设计大二,我在做一个图书馆管理系统.源代码是从互联网上下载,代码天天磨,隐约中记得有Socket这么一个单词. 第二次是去年代表学校參加"河北省电子信息职业技能大赛 ...
- 《学习opencv》笔记——矩阵和图像处理——cvAnd、cvAndS、cvAvg and cvAvgSdv
矩阵和图像的操作 (1)cvAnd函数 其结构 void cvAnd( //将src1和src2按像素点取"位与运算" const CvArr* src1,//第一个矩阵 cons ...
- SharePoint 2010 升级到2013时间 为了确保用户可以连接,但无法改变升级数据
SharePoint 2010 升级到2013时间 为了确保用户可以连接,但无法改变升级数据 我总结的步骤 红色请注意它们的含义. 步骤1:连接到SQL DBS 上的SharePoint 2010数据 ...