一、介绍
Quartz.net是Quartz的.net版本,主要用途是用来管理定时需要执行的任务,和数据库的job有点类似,他管理的任务包括但不限于数据,还可以包括类似于发送邮件,短信等任务,更可以查看任务状态,总而言之,是一个强大,开源且轻量级的任务调度框架。
官网:http://www.quartz-scheduler.net/
在园子里其实已经有很多人已经写过Quartz.net的相关文章了,在研究Quartz.net的过程中也借鉴了很多他们的相关经验,并将一些想法记录下来,以供以后参考。
二、简单的Job
[DisallowConcurrentExecutionAttribute] public class HelloJob: IJob { public Task Execute(IJobExecutionContext context) { Console.WriteLine("Info From HelloJob"); Thread.Sleep(30000); LogHelper.WriteInfo("Info From HelloJob"); return Task.FromResult(0); } }
普通的job继承IJob就可以,上面的代码是像系统中写日志,在控制台调用如下。
static void Main(string[] args) { //创建一个作业调度池 ISchedulerFactory schedf = new StdSchedulerFactory(); IScheduler sched = schedf.GetScheduler(); //创建出一个具体的作业 IJobDetail job = JobBuilder.Create().Build(); //配置一个触发器 ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithSimpleSchedule(x=>x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build(); //加入作业调度池中 sched.ScheduleJob(job, trigger); //开始运行 sched.Start(); Console.ReadKey(); }
其中调度器就是一个管理者,他管理着他控制范围内的所有的job的开始,暂停等信息。具体的作业,也就是上面的Job,这个Job会和一个触发器相关联,这个触发器用来控制Job的触发事件,触发次数等,在Quartz.net中有两种触发器类型,一种是简单触发器,也就是上面的ISimpleTrigger接口,还有一种是Cron类型的触发器,对应的接口名是ICronTrigger,他使用cron表达式来描述Job的触发事件,不了解cron表达式的可以百度具体代表的意思,这里就不详述了。
三、持久化job到本地
上面的代码只是Quartz的简单使用,但是不能可视化的控制调度池内的job。上面说到Quartz.net很强大,要想做到这一点也很简单,将job持久化到本地,将调度器,job详情,相关触发器的信息都抽象成数据存储在数据库中就行了。
quartz.net的github内提供了多种数据库的建表脚本,大家可以根据自己的需要去取,地址是:https://github.com/quartznet/quartznet/tree/master/database/tables,我用的是sqlServer版本的,只需要改一下数据库的名称就行。
表建好之后需要在程序中初始化相关配置,初始化的代码如下:
public async static TaskGetScheduler() { try { if (scheduler == null) { #region quartz 实例配置 还包括集群,线程池等配置,可单独放到config文件中配置 var properties = new NameValueCollection(); //存储类型 properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; properties["quartz.serializer.type"] = "binary"; //表明前缀 properties["quartz.jobStore.tablePrefix"] = "QRTZ_"; //驱动类型 properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; //数据源名称 properties["quartz.jobStore.dataSource"] = "Quartz"; //连接字符串 properties["quartz.dataSource.Quartz.connectionString"] = ConfigurationManager.AppSettings["quartzConnect"]; //sqlserver版本 properties["quartz.dataSource.Quartz.provider"] = "SqlServer"; //最大链接数 properties["quartz.dataSource.Quartz.maxConnections"] = "5"; #endregion ISchedulerFactory sf = new StdSchedulerFactory(properties); scheduler =await sf.GetScheduler(); LogHelper.WriteInfo(ConfigurationManager.AppSettings["quartzConnect"].ToString()); LogHelper.WriteInfo("任务调度初始化成功"); } } catch (Exception ex) { LogHelper.WriteError("任务调度初始化失败!", ex); } return scheduler; }
由于我从NuGet应用的Quartz是3.0.7.0版本的,方法都是异步的,所以都写成了异步方法(c#的异步还没怎么理解透彻,写法可能有误,请谅解)。这些配置因为版本经常会更新,所以不同的时期可能会有所不同,大家可以百度最新的配置。配置完成之后就可以调用该方法获取最新的调度器,然后对调度器内的Job进行控制了,详细的代码会文末会给出GitHub的地址,有需要的可以去GitHub上clone。
Job能够持久化了,如果代码只能点击exe文件运行,那持久化就没什么意义了,所以我选择使用Topshelf来创建一个服务,作为服务端来一直运行,服务启动时就初始化调度器。调用的代码如下:
static void Main(string[] args) { FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "Web.config"); XmlConfigurator.ConfigureAndWatch(fi); LogHelper.SetConfig(fi); HostFactory.Run(config => { config.Service(setting => { setting.ConstructUsing(name => new QuartzHelper()); setting.WhenStarted( tc => tc.start()); setting.WhenStopped( tc => tc.StopSchedule()); }); config.RunAsLocalSystem(); config.SetDescription("Quartz初使用"); config.SetDisplayName("QuartzService"); config.SetServiceName("QuartzService"); }); }
四、管理Job
持久化完成之后,就需要写个管理端来管理Job了,在这里我选择使用传统的MVC建一个管理端,为了图方便,我使用了晓道的管理端框架,页面如下:
这里的Job就是上面的HelloJob,需要说明一下的是,在新增的时候,类名需要和Job的名称保持一致,因为在代码中需要通过类名字段来反射找到dll文件中的Job,比如这里的类名我填的就是HelloJob,前面的命名空间不需要填。添加完成之后启动使用Topshelf创建的服务:
服务启动完成之后就可以看到记录的日志了:
五、末尾
要想更加深入了解Quartz.net的同学,可以看看张善友大神的系列文章。
代码已经上传到GitHub上了,GitHub的地址为:https://github.com/cpf121/Quartz.net-Demo 。代码拉下来后运行方式如下:
1.去GitHub取到最新的建表脚本,自己建表,并修改config文件中的连接语句
2.命令提示符使用管理员权限找到QuartzService文件夹下的QuartzService.exe文件,运行QuartzService.exe Install
3.在管理端添加对应的Job信息。