Quartz.Net(2)——NetCore3.1整合Quartz.Net

在上篇文章中Quartz.Net(1) 已经介绍了Quartz.Net的基本运用,该篇文章中将主要介绍NetCore3.1如何整合Quartz.Net,在后台运行定时job,并运用到上篇文章讲到的介绍点。

1 导入Nuget包

xml 复制代码
    <PackageReference Include="Quartz" Version="3.8.1" />
  
    <PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.8.1" />
    
    <PackageReference Include="Quartz.Extensions.Hosting" Version="3.8.1" />

Quartz 定时框架

Quartz.Extensions.DependencyInjection 用于在任务中导入其他的服务,整合使用NetCore的依赖注入框架

Quartz.Extensions.Hosting 使得Job在后台运行

.NetCore3.1 整合的版本均是3.8.1

2 定义Job

在定义Job时,用到了一个自定义特性JobAttribute,标注在实现了 I J o b \textcolor{red}{IJob} IJob类上,标明该任务的分组,名称,描述 ,触发器触发时的Corn表达式。

在实际运行的任务中将依赖于其他服务 如数据库服务、配置服务等,这里可以通过构造函数注入的方式引入其他的服务

csharp 复制代码
    /// <summary>
    /// 自定义特性,用来标注Job运行信息
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class JobAttribute: Attribute
    {
        /// <summary>
        /// Job运行的Corn表达式
        /// </summary>
        public string Corn { get; set; }

        /// <summary>
        /// Job组
        /// </summary>
        public string JobGroup { get; set; }

        /// <summary>
        /// Job名称
        /// </summary>
        public string JobName { get; set; }
        /// <summary>
        /// Job描述
        /// </summary>
        public string JobDesc { get; set; }

        public JobAttribute(string Corn) {
            this.Corn = Corn;
        }
    }
csharp 复制代码
    /// <summary>
    /// 新进员工创建用户刷脸照片Job 
    /// 每天6点、14点执行
    /// </summary>
    [Job("0 0 6,14 * * ? *", JobDesc = "新进员工创建用户刷脸照片Job", JobGroup = "group2", JobName = "AddJob")]
    public class CreatePhotoJob : IJob
    {

        private FaceContext faceContext;
        private FaceWebService faceWebService;
        private ILogger<DelLeftEmpPhotoJob> logger;
        private IConfiguration configuration;

        public CreatePhotoJob(FaceContext faceContext, FaceWebService faceWebService, ILogger<DelLeftEmpPhotoJob> logger, IConfiguration configuration)
        {
            this.faceContext = faceContext;
            this.faceWebService = faceWebService;
            this.logger = logger;
            this.configuration = configuration;
        }


        public async Task Execute(IJobExecutionContext context)
        {
            //忽略任务的具体执行逻辑
            await RunJob();
        }
    }
    
csharp 复制代码
    /// <summary>
    /// 删除离职人员刷脸照片Job
    /// 凌晨2点钟执行
    /// </summary>
    [Job("0 0 2 * * ? *", JobDesc = "删除离职人员刷脸照片Job",JobGroup ="group1",JobName ="DelJob")]
    public class DelLeftEmpPhotoJob : IJob
    {

        private FaceContext faceContext;
        private FaceWebService faceWebService;
        private ILogger<DelLeftEmpPhotoJob> logger;

        public DelLeftEmpPhotoJob(FaceContext faceContext, FaceWebService faceWebService, ILogger<DelLeftEmpPhotoJob> logger)
        {
            this.faceContext = faceContext;
            this.faceWebService = faceWebService;
            this.logger = logger;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            //忽略任务的具体执行逻辑
            await RunJob();
        }
}

3 定义JobListener

为了更好的监听任务的运行状态,比如说在任务运行结束时向开发人员推送邮件,这里用到了任务监听器。实现方式时实现一个IJobListener。具体的业务逻辑请忽略,这里只是给出一个思路。

csharp 复制代码
  /// <summary>
    /// 任务监听器,使用AOP的思想监听任务[IJob]运行前后的动作
    /// </summary>
    public class MyJobListener : IJobListener
    {
        public string Name => "JobListener";

        public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
        {
            //throw new NotImplementedException();

        }

        /**
         * 监听Job运行前
         */
        public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
        {
           // throw new NotImplementedException();
        }


        /**
         * 在这里执行任务结束后的操作
         * 根据JobDetail所在的分组与名称分别发送不同内容的邮件信息
         */
        public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
        {
            try
            {
                HRWebService webService = new HRWebService();
                var jobkey = context.JobDetail.Key;
                MailBody body = null ;
                if (jobkey.Group.Equals("group2") && jobkey.Name.Equals("AddJob"))
                {
                    body = MailBody.AddJobMail();
                }
                else if (jobkey.Group.Equals("group1") && jobkey.Name.Equals("DelJob"))
                {
                    body = MailBody.DelJobMail();
                }
                await webService.SendMail(body);
            }
            catch (Exception e) { 
               
            }
            
        }
    }

3 配置服务

为了运行定义的IJob 示例,需要注册服务,触发器,监听器等信息,通常是在startup中进行配置。为了避免在startup中进行关于Quartz复杂的配置,这里将Job配置,触发器的配置等配置服务抽离到一个单独的配置类中,运用到了反射的思想。

csharp 复制代码
    /// <summary>
    /// Quartz.Net 定时Job配置类
    /// </summary>
    public static class QuartzConfiguration
    {

        public static IServiceCollection AddMyQuartz(this IServiceCollection services) 
        {

            //读取所有实现IJob接口的类,类上标注了JobAttribute类,调度器使用corn触发器去触发JOB任务
               //FaceJob是我定义Job的模块,这里只做参考,实际读取IJob的反射Type可能各不相同
            AssemblyName assemblyName = new AssemblyName("FaceJob");
            Assembly anotherModuleAssembly = Assembly.Load(assemblyName);
            var types = anotherModuleAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob)))
                .Where(t => t.GetCustomAttribute<JobAttribute>() != null).ToArray();

            services.AddQuartz(configure =>
            {
                 
                 //Quartz3.8.1版本 默认是使用NetCore的依赖注入框架的,因此可以不用显示的定义此信息,但是在3.3.2及之前版本,不显示定义此配置是无法在Job中引入其他服务的
                 //configure.UseMicrosoftDependencyInjectionJobFactory();

                foreach (Type type in types)
                {
                    //读取IJob上定jobAttribute(标注Job运行的信息) 
                    JobAttribute jobAttribute = type.GetCustomAttribute<JobAttribute>();
                    var jobKey = new JobKey(jobAttribute.JobName, jobAttribute.JobGroup);

                    //配置Job
                    configure.AddJob(type, jobKey, config =>
                    {
                        config.WithDescription(jobAttribute.JobDesc);
                    });


                    //配置触发器,统一使用Corn触发器
                    configure.AddTrigger(config =>
                    {
                        config.ForJob(jobKey)
                        .WithCronSchedule(jobAttribute.Corn);
                    });

                }
                //配置job监听器[监听任意组下的Job]
                configure.AddJobListener<MyJobListener>(GroupMatcher<JobKey>.AnyGroup());

            });


            //后台Job,任务在后台运行
            services.AddQuartzHostedService(options =>
            {
                options.WaitForJobsToComplete = true;
            });
            return services;
        } 
    }

在startup中引入Quartz配置

csharp 复制代码
        public void ConfigureServices(IServiceCollection services)
        {
            //忽略其他服务配置
            #region Quartz服务配置
            services.AddMyQuartz();
            #endregion

        }
相关推荐
万雅虎2 个月前
使用 `Roslyn` 分析器和修复器 对异步方法规范化返回Async结尾
netcore·roslyn·csharp·sg
Mudrock__2 个月前
Quartz.Net_持久化
.net·quartz.net
Mudrock__2 个月前
Quartz.Net_侦听触发器
.net·quartz.net
ggtc3 个月前
前后端分离项目,后期前端身份验证的麻烦
前后端分离·身份认证·netcore
gc_22993 个月前
C#测试控制台程序调用Quartz.NET的基本用法
c#·quartz.net
ggtc4 个月前
WebRTC入门
webrtc·netcore
万雅虎5 个月前
NET8中增加的简单适用的DI扩展库Microsoft.Extensions.DependencyInjection.AutoActivation
netcore·aspnetcore
万雅虎5 个月前
NET9 提供HybridCache解决分布式缓存中存在的远程链接&序列化带来的性能问题
netcore·aspnetcore·net9
ggtc5 个月前
基于WebSocket的modbus通信(二)- 客户端
modbustcp·websocket·netcore
ggtc5 个月前
基于WebSocket的modbus通信(一)- 服务器
websocket·c#·modbus·netcore