.NET开源作业调度框架Quartz

.NET开源作业调度框架Quartz

一 Quartz简介

在这里插入图片描述

  • Quartz是一个强大、开源、轻量的作业调度框架,你能够用它来为执行一个简单或复杂的作业调度任务。

  • 是对非常流行的JAVA开源调度框架 Quartz 的移植。

  • 它有很多特征,如:数据库支持,集群,插件,支持Cron-like表达式等等。非常适合在平时的工作中,做定时轮询数据库同步,定时邮件通知,定时数据处理等操作。

  • 允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。

官网: http://www.quartz-scheduler.net/

源码: https://github.com/quartznet/quartznet

示例: https://www.quartz-scheduler.net/documentation/quartz-3.x/quick-start.html

1 运行时环境

在这里插入图片描述

运行时环境

Quartz.NET 从3.0版本开始支持Standard 2.0

Quartz.NET 3.0 既可以在.NetFarmerwork上运行,也可以在.NetCore项目上运行

2 三个基础概念

  • 任务:需要执行的任务。

  • 触发器:触发器用于配置调度参数,设置触发条件。

  • 调度器:调度器将对应的触发器和任务绑定在一起,当触发器被触发时执行对应的任务。

在这里插入图片描述
•Job 为作业的接口,JobDetail 用来描述 Job 的实现类及其它相关的静态信息;

•Trigger 作为作业的定时管理工具,一个 Trigger 只能对应一个作业实例,而一个作业实例可对应多个 Trigger ;

•Scheduler 做为定时任务容器,它包含了所有触发器和作业,每个 Scheduler 都存有 JobDetail 和 Trigger的注册,一个 Scheduler 中可以注册多个 JobDetail 和多个 Trigger 。

3 Trigger任务触发器

lSimpleTrigger 设置一些简单的属性,如开始时间、结束时间、重复次数、重复间隔等。

•name(必填) 触发器名称,同一个分组中的名称必须不同

•group(选填) 触发器组

•description(选填) 触发器描述

•job-name(必填) 要调度的任务名称,该job-name必须和对应job节点中的name完全相同

•job-group(选填) 调度任务(job)所属分组,该值必须和job中的group完全相同

•start-time(选填) 任务开始执行时间utc时间,北京时间需要+08:00,如:2012-04-01T08:00:00+08:00表示北京时间2012年4月1日上午8:00开始执行,注意服务启动或重启时都会检测此属性,若没有设置此属性或者start-time设置的时间比当前时间较早,则服务启动后会立即执行一次调度,若设置的时间比当前时间晚,服务会等到设置时间相同后才会第一次执行任务,一般若无特殊需要请不要设置此属性

•repeat-count(必填) 任务执行次数,如:-1表示无限次执行,10表示执行10次

•repeat-interval(必填) 任务触发间隔(毫秒),如:10000 每10秒执行一次

lCronTrigger 复杂任务触发器–使用cron表达式定制任务调度(强烈推荐)

•name(必填) 触发器名称,同一个分组中的名称必须不同

•group(选填) 触发器组

•description(选填) 触发器描述

•job-name(必填) 要调度的任务名称,该job-name必须和对应job节点中的name完全相同

•job-group(选填) 调度任务(job)所属分组,该值必须和job中的group完全相同

•start-time(选填) 任务开始执行时间utc时间,北京时间需要+08:00,如:2012-04-01T08:00:00+08:00表示北京时间2012年4月1日上午8:00开始执行,注意服务启动或重启时都会检测此属性,若没有设置此属性,服务会根据cron-expression的设置执行任务调度;若start-time设置的时间比当前时间较早,则服务启动后会忽略掉cron-expression设置,立即执行一次调度,之后再根据cron-expression执行任务调度;若设置的时间比当前时间晚,则服务会在到达设置时间相同后才会应用cron-expression,根据规则执行任务调度,一般若无特殊需要请不要设置此属性

•cron-expression(必填) cron表达式,如:0/10 * * * * ?每10秒执行一次

4 监听器

任务调度框架并不是完美的,它也会出现任务执行失败的情况。如果你需要处理任务失败后的逻辑,这个时候监听器就发挥作用了。Quartz的监听器用于当任务调度中你所关注事件发生时,能够及时获取这一事件的通知。包括像任务执行前、执行中、执行后、执行异常等事件的通知。

种类

Quartz监听器主要有以下三种,分别表示任务、触发器、调度器对应的监听器。

lJobListener:任务调度过程中,与任务Job相关的事件包括job开始要执行的提示,job执行完成的提示。

lTriggerListener:任务调度过程中,与触发器Trigger相关的事件包括触发器触发、触发器未正常触发、触发器完成等。

lSchedulerListener:会在Scheduler的生命周期中关键事件发生时被调用。与Scheduler有关的事件包括:增加一个job/trigger,删除一个job/trigger,scheduler发生严重错误,关闭scheduler等。

  • 全局监听器:能够接收到所有的Job/Trigger的事件通知

  • 非全局监听器:只能接收到在其上注册的Job或Trigger的事件,不在其上注册的Job或Trigger则不会进行监听。

对于非全局的 JobListener,它应于任何引用到它的 JobDetail 使用 schedulerJob() 或 addJob() 方法注册之前被注册。

5 Quartz API 的主要接口和类如下

IScheduler - 和调度器交互的主要API

IJob - 调度器会执行实现这个接口的实例

IJobDetail - 用来定义任务的实例

ITrigger - 定义任务执行安排的组件

JobBuilder - 用来定义/构造JobDetail的实例,其中JobDetail的实例定义Jobs的实例

TriggerBuilder - 用来定义/构造Trigger的实例

在这里插入图片描述

6 依赖框架

  • 引入框架的方法非常简单你可以直接用NuGet管理包也可以在项目中添加引用。

  • 点击“工具”->“NuGet包管理器”->“程序包管理器控制台”
    在这里插入图片描述

输入安装包的命令:

Install-Package Quartz

二 Quartz应用

五步创建Quartz应用

  • 创建一个调度器
  • 定义要执行的任务
  • 创建一个任务对象
  • 创建一个触发器
  • 将任务与触发器添加到调度器中并执行

1 创建一个Scheduler任务调度容器

            StdSchedulerFactory factory = new StdSchedulerFactory();
            //创建一个Scheduler任务调度容器
            IScheduler scheduler = await factory.GetScheduler();

2 定义要执行的任务

定义一个类,实现IJob接口,实现方法Execute,代码如下:

using Quartz;
namespace QuartZDemo.Web.Jobs
{
    //增加特性保证任务不会重叠执行
    [DisallowConcurrentExecution]
    public class SendMailJob : IJob
    {
        //Job类
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
            {
                //doSomthing
                Console.WriteLine($"开始发送邮件{DateTime.Now}");
            });
        }
    }
}

3 创建一个任务对象

这个任务对象就是我们将要执行的工作,job1是名称,group1是组名。

 			//指定具体执行的任务Job
            IJobDetail sendEmailJob = JobBuilder.Create<SendMailJob>()
            .WithIdentity("sendEmailJob", "sendEmailJobGrop")
            .WithDescription("定时发送邮件").Build();

4 创建一个触发器

触发器定义了什么时间任务开始或每隔多久执行一次。

  //设置触发条件为五秒执行一次
            ITrigger sendEmailTrigger = TriggerBuilder.Create()
            .WithIdentity("sendEmailTrigger", "sendEmailJobGrop")
            .WithDescription("QuartZ")
            .WithCronSchedule("*/5 * * * * ?")
            .Build();

5 将任务与触发器添加到调度器中并执行

			 //把策略和任务放入到Scheduler
            await scheduler.ScheduleJob(sendEmailJob, sendEmailTrigger);
            //执行任务
            await scheduler.Start();

三 Cron表达式

1 Cron表达式结构

Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
Seconds Minutes Hours DayofMonth Month DayofWeek
Seconds Minutes Hours DayofMonth Month DayofWeek Year
Cron表达式从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份

2 各字段的含义

在这里插入图片描述

3 特殊符号解释

*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。

? :只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
,:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

4 注意要点

  • 单个子表达式可以包含范围或者列表。例如:前面例子中的周中的天这个域(这里是“WED”)可以被替换为MON-FRI,“MON,WED,FRI”或者甚至MON-WED,SAT。
  • Cron表达式全程Crontab表达式,是描述Crontab定时任务执行周期的一种语法格式。而Cron表达式严格上来说有许多特别的版本。如:Linux的、Spring的、Quartz框架等表达式,虽说它们总体上来说一类似的,但总会有一些语法的差异在里面。而本文要介绍的是基于Quartz 的Cron表达式。

5 Cron表达式示例

// 秒 分 时 月份中的日期 月 周的天数 年(默认可以不填写)
//注意:一般月份中的日期会和周的天数冲突
“0 0 10,14,16 * * ?” 每天上午10点,下午2点,4点
“0 0/30 9-17 * * ?” 朝九晚五工作时间内每半小时,从0分开始每隔30分钟发送一次
“0 0 12 ? * WED” 表示每个星期三中午12点
“0 0 12 * * ?” 每天中午12点触发
“0 15 10 ? * *” 每天上午10:15触发
“0 15 10 * * ?” 每天上午10:15触发
“0 15 10 * * ? *” 每天上午10:15触发
“0 15 10 * * ? 2005” 2005年的每天上午10:15触发
“0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
“0 0/55 14 * * ?” 在每天下午2点到下午2:59期间,从0开始到55分钟触发
“0 0/55 14,18 * * ?” 在每天下午2点到下午2:59期间和下午6点到6:55期间,从0开始到55分钟触发
“0 0-5 14 * * ?” 在每天下午2点到下午2:05期间的每1分钟触发
“0 10,44 14 ? 3 WED” 每年3月的星期三的下午2:10和2:44触发
“0 15 10 ? * MON-FRI” 周一到周五的上午10:15触发
“0 15 10 15 * ?” 每月15日上午10:15触发
“0 15 10 L * ?” 每月最后一日的上午10:15触发
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发

6 表达式生成器

有很多的Cron表达式在线生成器,这里给大家推荐几款:
https://www.pppet.net/
https://www.bejson.com/othertools/cron/

四 Quartz持久化与集群

在这里插入图片描述

1 QuartZ持久化

能保证实例重启后job不丢失、 负载均衡缓解服务器压力和解决单点故障问题。

  • Quartz集群中每个节点是一个独立的Quartz任务应用,该集群需要对每个节点分别启动或停止。
  • 独立的Quartz节点并不与另一个节点或是管理节点通信。Quartz应用是通过共有相同数据库表来感知到另一应用。
  • 也就是说只有使用持久化JobStore存储Job和Trigger才能完成Quartz集群。

2 JobStore介绍

用于追踪任务调度相关的所有数据,Quartz提供了两种:

  • RAMJobStore
      RAMJobStore是最简单的JobStore,顾名思义这种JobStore将所有的数据都存放在内存中,这也是它运行速度快的原因,但是弊端也很明显:一旦应用结束或者遇到断电所有的数据都会丢失。RAMJobStore是默认的JobStore,我们也已通过下边的代码来显式设置使用的JobStore为RAMJobStore。
    quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz

  • AdoJobStore
      AdoJobStore通过Ado.net将数据存储在数据库中,因此可以解决断电数据丢失的问题,但是因为要读写数据库所以效率相对较低。AdoJobStore官方支持的数据库有:MySql,SqlServer,Sqllite,Oracle等,当前AdoJobStore只有一种类型JobStoreTX,这一点不同于Jave版本,java版本还有JobStoreCMT类型。

  • 官方提供的各种数据库脚本
    https://github.com/quartznet/quartznet/tree/master/database/tables

3 数据库表说明

Table nameDescription
qrtz_blob_triggers用来存储Trigger作为Blob类型(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)。
qrtz_calendars用来存储日历信息, quartz可配置一个日历来指定一个时间范围。
qrtz_cron_triggers用来存储触发器 Cron表达式和时区信息。如:调度名称、触发器名称、分组、cron表达式、时区等
qrtz_fired_triggers用来存储已触发的Trigger相关的状态信息,以及相关联Job的执行信息。
qrtz_job_details用来存储已配置的Job的详细信息。如:调度名称、集群中job的名称、分组、是否持久化、是否并发等
qrtz_locks用来存储程序的悲观锁的信息(假如使用了悲观锁)。包括:调度名称、悲观锁名称
qrtz_paused_trigger_grps用来存储已暂停的Trigger组的信息。包括:调度名称、触发器所属组的名称,qrtz_triggers表的TRIGGER_GROUP的外键
qrtz_scheduler_state用来存储集群中调度实例信息,quartz会定时读取该表的信息判断集群中每个实例的当前状态。包括:调度名称、调度实例id、上次检查时间、检查间隔时间
qrtz_simple_triggers用来存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数。
qrtz_simprop_triggers用来存储存储CalendarIntervalTrigger和DailyTimeIntervalTrigger。
qrtz_triggers用来存储触发器的基本信息。如:调度名称、触发器名称、分组、上一次&下一次触发时间,优先级,开始&结束时间等

4 上代码

  • 创建 JobManager.cs
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace QuartZDemo.Console.Jobs
{
    public  class JobManager
    {
        public Task<IScheduler> GetScheduler()
        {
            try
            {
                //1.首先创建一个作业调度池
                var properties = new NameValueCollection();
                //schedule名称
                properties["quartz.scheduler.instanceName"] = "MyScheduler";

                //自动生成scheduler实例ID,主要为了保证集群中的实例具有唯一标识
                properties["quartz.scheduler.instanceId"] = "AUTO";

                properties["quartz.threadPool.type"] = "Quartz.Simpl.DefaultThreadPool, Quartz";

                //线程池个数
                properties["quartz.threadPool.threadCount"] = "20";

                properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX,Quartz";
                //表明前缀
                properties["quartz.jobStore.tablePrefix"] = "QRTZ_";
                // 序列化类型,必须添加,不添加无法注册数据库
                properties["quartz.serializer.type"] = "binary"; 
                //驱动类型
                properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.MySQLDelegate,Quartz";
                //数据源名称
                properties["quartz.jobStore.dataSource"] = "quartznet";

                //是否配置集群
                properties["quartz.jobStore.clustered"] = "true";

                properties["quartz.jobStore.clusterCheckinInterval"] = "5000";
                //连接字符串             
                properties["quartz.dataSource.quartznet.connectionString"] = "Database=quartznet;Data Source=127.0.0.1;Port=3306;User Id=root;Password=forever@123456;Charset=utf8;TreatTinyAsBoolean=false;";
                //版本
                properties["quartz.dataSource.quartznet.provider"] = "MySql";
                //最大链接数
                properties["quartz.dataSource.quartznet.maxConnections"] = "100";

                ISchedulerFactory factory = new StdSchedulerFactory(properties);
                return factory.GetScheduler();
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex);
                throw;
            }
        }


    }
}
  • 创建任务SendMailJob.cs
using Quartz;

namespace QuartZDemo.Console.Jobs
{
    //增加特性保证任务不会重叠执行
    [DisallowConcurrentExecution]
    public class SendMailJob : IJob
    {
        //Job类
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
            {
                //doSomthing
                System.Console.WriteLine($"开始发送邮件{DateTime.Now}");
            });
        }
    }
}
  • 执行任务Program.cs

    // See https://aka.ms/new-console-template for more information
    using Quartz;
    using Quartz.Impl;
    using QuartZDemo.Console.Jobs;
    
    Console.WriteLine("begin************************");
    
    IScheduler scheduler = new JobManager().GetScheduler().Result;
    scheduler.Start();
    
    //指定具体执行的任务Job
    IJobDetail sendEmailJob = JobBuilder.Create<SendMailJob>()
    .WithIdentity("sendEmailJob", "sendEmailJobGrop")
    .WithDescription("定时发送邮件").Build();
    
    //设置触发条件为五秒执行一次
    ITrigger sendEmailTrigger = TriggerBuilder.Create()
    .WithIdentity("sendEmailTrigger", "sendEmailJobGrop")
    .WithDescription("QuartZ")
    .WithCronSchedule("*/3 * * * * ?")
    .Build();
    
    if (scheduler.CheckExists(sendEmailJob.Key).Result)
    {
        scheduler.DeleteJob(sendEmailJob.Key).Wait();
    }
    scheduler.ScheduleJob(sendEmailJob, sendEmailTrigger).Wait();
    
    
    Console.WriteLine("end**************************");
    Console.ReadKey();
    
    

5 创建Quartz表数据

运行程序Quartz会自动在数据库中记录调度任务相关的数据

  • Quartz自动向数据库写入的trigger信息:

在这里插入图片描述

  • Quartz自动向数据库写入的Job信息:

在这里插入图片描述

  • 程序执行结果:

在这里插入图片描述

  • 到这里我们看到了Db持久化已经实现了,但是上边的例子,我们在代码中通过 [“quartz.jobStore.clustered”] = “true” 配置了集群,这个有什么用呢?首先添加一个debug文件夹的副本

在这里插入图片描述

  • 然后运行这两个文件夹下的xxx.exe文件(如果使用的是.net core,生成的是xxx.dll文件,进入dll文件所在目录,命
    令行运行 dotnet xxx.dll 即可启动),运行结果如下:

在这里插入图片描述

  • 如上所示,运行两个xxx.exe(core中是dll)后,原文件和副本在同一时间只有一个在运行,所以我们调度的任务没有重复执行。如果我们关掉正在执行的那个程序,那么另一个程序会开始执行。我们可以得出结论:Quartz的集群并不会造成任务重复执行,而且当一个服务器挂了后,另一个服务器会自动开始执行,这种机制大大增加了任务调度的容灾性能。

6 注意问题

  • 1.Quartz3.x支持async和await,为提高性能,我们最好将Job中的Execute方法都写成异步方法;
  • 2.不管使用的是RAMJobStore还是AdoJobStore,千万不要通过代码来直接操作JobStore(比如我们直接通过代码修改数据库中的数据),JobStore让Quartz自动操作即可。无论使用场景是web应用还是桌面程序,我们只使用Scheduler提供的接口方法来实现Job和Trigger等的增/删/改/查/暂停/恢复即可。
  • 3.时间同步问题
    Quartz实际并不关心你是在相同还是不同的机器上运行节点。当集群放置在不同的机器上时,称之为水平集群。节点跑在同一台机器上时,称之为垂直集群。对于垂直集群,存在着单点故障的问题。这对高可用性的应用来说是无法接受的,因为一旦机器崩溃了,所有的节点也就被终止了。对于水平集群,存在着时间同步问题。节点用时间戳来通知其他实例它自己的最后检入时间。假如节点的时钟被设置为将来的时间,那么运行中的Scheduler将再也意识不到那个结点已经宕掉了。另一方面,如果某个节点的时钟被设置为过去的时间,也许另一节点就会认定那个节点已宕掉并试图接过它的Job重运行。最简单的同步计算机时钟的方式是使用某一个Internet时间服务器(Internet Time Server ITS)。
  • 4.节点争抢Job问题
    因为Quartz使用了一个随机的负载均衡算法,Job以随机的方式由不同的实例执行。Quartz官网上提到当前,还不存在一个方法来指派(钉住) 一个 Job 到集群中特定的节点。

五 Quartz部署模式

1 IIS部署

在MVC框架中集成了Quartz定时调度,此时该调度系统会随着MVC框架被挂在IIS下,IIS会进程回收,所以大部分开发都会遇到Quartz挂在IIS下一段时间不好用。
  
**补充:**IIS可以设置定时自动回收,默认回收是1740分钟,也就是29小时。IIS自动回收相当于服务器IIS重启,应用程序池内存清空,所有数据被清除,相当于IIS重启,在度量快速开发平台服务器端,为了减小数据库负担,内存中暂存了很多信息,不适合频繁的回收,因为回收会造成服务器端所有存在内存中的数据丢失,如果没有及时保存到数据库中,可能导致程序出现问题。而如果系统使用高峰时期,并不适合回收,回收可能导致几十秒IIS无响应,对于正在工作的人员来说,是一种很不好的体验,会以为是网络或者掉线等问题。

解决方案:关闭该项目在IIS上对应的进程池的回收机制。
如何关闭进程池的回收机制:选中IIS中部署的项目对应的进程池,点击【高级设置】,里面有5个核心参数:

在这里插入图片描述

① 发生配置更改时禁止回收:如果为True,应用程序池在发生配置更改时将不会回收。
② 固定时间间隔(分钟):超过设置的时间后,应用程序池回收,设置为:0 意味着应用程序池不回收。系统默认设置的时间是1740(29小时)。
③ 禁用重叠回收:如果为true,将发生应用程序池回收,以便在创建另一个工作进程之前退出现有工作进程
④ 请求限制:应用程序池在回收之前可以处理的最大请求数。如果值为0,则表示应用程序池可以处理的请求数没有限制。
⑤ 生成回收事件日志条目:每发生一次指定的回收事件时便产生一个事件日志条目。

总结:即使可以将IIS进程池回收关掉,仍然不建议把Quartz挂到IIS下,长时间不回收,会存在内存溢出的问题。

2 C/S程序直接运行

用控制台的形式或者Winform的形式单独做一套定时调度系统,与主框架分类,也便于维护,可以直接将exe程序或者Winform窗体程序在服务器上运行。
**总结:**该方法不存在回收的问题,但直接在服务器上运行,容易不小心被运维人员关掉了。

3 借助topshelf来进行的windows服务部署

  1. 通过NuGet下载 Topshelf 的程序集
  2. 配置QuartzService类,充当定时任务的服务端程序
  3. 在主程序中通过topshelf代码调用:HostFactory.Run 详见主程序。(在里面可以设置服务的名称、描述等)
  4. 通过指令进行服务发布和卸载(查看windows服务:services.msc)

4 Worker Service 部署(推荐)

  • 什么是Worker Service?
    Worker Service 是使用模板构建的 .NET 项目,该模板提供了一些有用的功能,可以将常规控制台应用程序变得更加强大。Worker Service 运行于宿主(Host)的概念之上,宿主维护应用程序的生命周期。宿主还提供了一些常见的特性,如依赖注入、日志记录和配置。
    Worker Service 通常是长时间运行的服务,执行一些规律发生的工作负载。
  • 部署依赖
    Microsoft.Extensions.Hosting.WindowsServices(windows平台下的服务)
    Microsoft.Extensions.Hosting.Systemd(linux平台下的服务)

根据自己需要选择添加,也可以都添加,判断平台注入服务。

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
        	//是否是windows平台
            bool isWinPlantform = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
            Console.WriteLine($"Window Plantform:{isWinPlantform}");
            if (isWinPlantform)
                return Host.CreateDefaultBuilder(args)
                    .UseSystemd()//使用linux服务
                    .ConfigureServices((hostContext, services) =>
                    {
                        services.AddHostedService<Worker>();
                    });
            return Host.CreateDefaultBuilder(args)
                .UseWindowsService()//使用windows服务
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
        }
    }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Quartz.NET是一个开源作业调度框架,它可以帮助我们实现定时任务和作业调度。在Quartz.NET中,我们可以通过实现IJob接口来定义一个作业,并且可以通过JobDataMap来传递参数。这篇文章将介绍如何在Quartz.NET中使用IJobExecutionContext来传递参数。 在Quartz.NET中,每次执行一个作业,都会创建一个新的JobExecutionContext对象。这个对象包含了当前作业的执行环境信息,包括作业的JobDetail信息、Trigger信息、Scheduler信息等等。除此之外,JobExecutionContext还提供了一个JobDataMap对象,用于存储传递给作业的参数。 下面是一个简单的示例,演示了如何在作业中获取JobDataMap中的值: ```csharp public class MyJob : IJob { public void Execute(IJobExecutionContext context) { JobDataMap dataMap = context.JobDetail.JobDataMap; string param1 = dataMap.GetString("param1"); int param2 = dataMap.GetInt("param2"); // 使用传递的参数执行作业逻辑 // ... } } ``` 在这个示例中,我们定义了一个作业MyJob,并实现了IJob接口。在Execute方法中,我们通过JobExecutionContext对象获取了JobDataMap,并从中获取了传递给作业的参数。接下来,我们可以使用这些参数执行作业逻辑。 除了JobDataMap之外,JobExecutionContext还提供了许多其他有用的信息,例如当前作业的执行时间、上次执行时间、下次执行时间等等。我们可以根据这些信息来编写更加复杂的作业逻辑。 总之,使用IJobExecutionContext可以方便地在Quartz.NET中传递参数,并且获取作业的执行环境信息。如果你想了解更多关于Quartz.NET的内容,可以参考Quartz.NET官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值