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

        }
相关推荐
ggtc5 天前
新能源电池壳冲压车间看板实施
vue·netcore·看板·车间
ggtc2 个月前
冲压车间软件实施
vue·netcore·工厂
sanzk2 个月前
Quartz.NET 核心功能与应用解析
quartz.net
sanzk2 个月前
quartz.net条件执行
quartz.net
小乖兽技术6 个月前
快速掌握Quartz.Net计划任务调度框架,轻松实现定时任务
.net·定时任务·quartz.net
万雅虎6 个月前
ASP.NET Core 9.0 中新增的MapStaticAssets() 中间件
netcore·aspnetcore·net9
万雅虎9 个月前
使用 `Roslyn` 分析器和修复器 对异步方法规范化返回Async结尾
netcore·roslyn·csharp·sg
Mudrock__9 个月前
Quartz.Net_持久化
.net·quartz.net
Mudrock__9 个月前
Quartz.Net_侦听触发器
.net·quartz.net
ggtc10 个月前
前后端分离项目,后期前端身份验证的麻烦
前后端分离·身份认证·netcore