Uwl.Admin.Core中使用QuartzNet定时任务模块

本文负责讲解RabbitMQ的使用

Uwl.Admin.Core使用的技术有:

  *、Async和Await 异步编程

  *、Repository + Service 仓储模式编程;仓储模式支持工作单元

  *、Swagger 前后端文档说明,基于RESTful风格编写接口

  *、Cors 简单的跨域解决方案

  *、JWT自定义策略授权权限验证

  *、依赖注入选择的是官方自带的DI注入,没有使用第三方框架,ORM使用EF Core,数据库使用的是Sql server,(后期会扩展MySql版本);

  *、AutoMapper 自动对象映射、

  *、Linq To Sql \ lambda表达式树查询;(表达式树查询是个人扩展的,表达式树的使用方法请参考Uwl.Data.Server.MenuServer的多条件查询)

  *、登录认证方式使用JWT认证方式,后台接口使用SwaggerUI展示,角色权限使用  自定义权限处理器PermissionHandler 继承与微软官方 IAuthorizationRequirement;

  *、Excel导入导出使用的是Epplus第三方框架,导入导出只需要配置Attribute特性就好,不需要在自己写列名;导出只支持List导出,暂时不支持Datatable;(Excel使用方法请参考UserController控制器)

  *、Rabbit MQ消息队列(目前暂无业务使用场景后期准备用来记录日志)

  *、Redis 轻量级分布式缓存;(Redis使用方法请参考Uwl.Data.Server.MenuServer类)

  *、QuartzNet第三方任务框架;(使用方法请参考类库Uwl.ScheduledTask.Job.TestJobOne类)

  *、IdentityServer4授权模式已开发完成,未发布演示服务器代码在github;(Identityserver4Auth分支)

Quartz.NET:

Quartz.NET官网地址:https://www.quartz-scheduler.net/

Quartz.NET文档地址:https://www.quartz-scheduler.net/documentation/index.html

Quartz.NET是一个开源的作业调度框架,是OpenSymphonyQuartz API的.NET移植,它用C#写成,可用于winformasp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。

现在Quartz.NET3.0已支持Asp.Net Core,3.0新功能如下:

新功能

  • 具有异步/等待支持的基于任务的作业,内部以异步/等待方式工作
  • 支持.NET Core / netstandard 2.0和.NET Framework 4.5.2及更高版本
  • 通过提供程序名称SQLite-Microsoft支持Microsoft.Data.Sqlite,旧的提供程序SQLite也仍然有效
  • 增加了SQL Server内存优化表和Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT的初步支持
  • Common.Logging从相关性中删除
  • ILMerge进程中删除的C5集合不再需要
  • 在插件启动时添加对作业调度XML文件的急切验证的支持
  • TimeZoneUtil中添加对额外的自定义时区解析器功能的支持

变化

  • 作业和插件现在位于独立的程序集NuGetQuartz.JobsQuartz.Plugins
  • ADO.NET提供者名称已被简化,提供者名称没有版本,例如SqlServer-20 => SqlServer
  • API方法已被重新使用,主要使用IReadOnlyCollection,这隐藏了两个HashSets和List小号
  • LibLog一直隐藏于内部(ILog等),就像它原本打算的那样
  • SimpleThreadPool消失了,旧的拥有的线程消失了
  • 调度程序方法已更改为基于任务,请记住等待它们
  • IJob接口现在返回一个任务
  • 一些IList属性已更改为IReadOnlyList以正确反映意图
  • SQL Server CE支持已被删除
  • DailyCalendar现在将日期时间用于排除的日期,并具有ISet接口来访问它们
  • IObjectSerializer有新的方法,void Initialize(),必须实现
  • IInterruptableJob取消了上下文的CancellationToken

Quartz API的关键接口和类是

  • IScheduler - 与调度程序交互的主要API。
  • IJob - 您希望由调度程序执行的组件实现的接口。
  • IJobDetail - 用于定义作业的实例。
  • ITrigger - 定义执行给定Job的时间表的组件。
  • JobBuilder - 用于定义/构建定义作业实例的JobDetail实例。
  • TriggerBuilder - 用于定义/构建触发器实例

一、Quartz.NET基本使用

  1、新建Uwl.QuartzNet.JobCenter 类库项目,使用NuGet添加Quartz,或使用程序包管理器引用,命令如下:

  Install-Package Quartz

  2、Uwl.QuartzNet.JobCenter 类库的作用:

   Uwl.QuartzNet.JobCenter 类库是计划任务管理中心,这里我就放一段代码了,不放太多,具体的实现可以下载下来Uwl.Admin.Core项目看
    /// <summary>
        /// 开启任务调度
        /// </summary>
        /// <returns></returns>
        public async Task<JobResuleModel> StartScheduleAsync()
        {
            var result = new JobResuleModel();
            try
            {
                if (!this._scheduler.Result.IsStarted)
                {
                    //等待任务运行完成
                    await this._scheduler.Result.Start();
                    await Console.Out.WriteLineAsync("任务调度开启!");
                    result.IsSuccess = true;
                    result.Message = $"任务调度开启成功";
                    return result;
                }
                else
                {
                    result.IsSuccess = false;
                    result.Message = $"任务调度已经开启";
                    return result;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

如果你想添加JSON序列化,只需要以同样的方式添加Quartz.Serialization.Json包。

2、简单实例,代码如下:
using Five.QuartzNetJob.ExecuteJobTask.Service;
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Threading.Tasks; namespace Five.QuartzNetJob.Web.Controllers
{
public class TestTask
{
public async Task StartTestAsync()
{
try
{
// 从工厂中获取调度程序实例
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
IScheduler scheduler = await factory.GetScheduler(); // 开启调度器
await scheduler.Start(); // 定义这个工作,并将其绑定到我们的IJob实现类
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1", "group1")
.Build(); // 触发作业立即运行,然后每10秒重复一次,无限循环
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build(); // 告诉Quartz使用我们的触发器来安排作业
await scheduler.ScheduleJob(job, trigger); // 等待60秒
await Task.Delay(TimeSpan.FromSeconds(60)); // 关闭调度程序
await scheduler.Shutdown();
}
catch (SchedulerException se)
{
await Console.Error.WriteLineAsync(se.ToString());
}
}
}
}

TestJobOne内容如下:

using Quartz;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Uwl.Common.Cache.RedisCache;
using Uwl.Common.Subscription;
using Uwl.Data.Server.MenuServices;

namespace Uwl.ScheduledTask.Job
{
    public class TestJobOne : IJob
    {
        private readonly IRedisCacheManager _redisCacheManager;
        private readonly IMenuServer _menuServer;
        public TestJobOne(IRedisCacheManager redisCacheManager,IMenuServer menuServer)
        {
            this._redisCacheManager = redisCacheManager;
            this._menuServer = menuServer;
        }
        public async Task Execute(IJobExecutionContext context)
        {
            //记录Job时间
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            
            await Console.Out.WriteLineAsync("我是有Redis的注入测试任务");
            var list = await _menuServer.GetMenuList();
            await Console.Out.WriteLineAsync("菜单表里总数量" + list.Count.ToString());
            stopwatch.Stop();
            await Console.Out.WriteLineAsync("执行时间" +  stopwatch.Elapsed.TotalMilliseconds);
            //if (stopwatch.Elapsed.TotalMilliseconds > 0)
            //{
            //    //写入日志性能监控表和执行是否出错
            //}
        }
    }
}

执行效果:

二、触发器类型

1、SimpleTrigger触发器(简单触发器)

SimpleTrigger的属性包括:开始时间和结束时间,重复计数和重复间隔。重复计数可以是零,一个正整数或常数值SimpleTrigger.RepeatIndefinitely。重复时间间隔属性必须是TimeSpan.Zero或正的TimeSpan值。请注意,重复间隔为0会导致触发器的“重复计数”触发同时发生。SimpleTrigger实例使用TriggerBuilder(用于触发器的主属性)和WithSimpleSchedule扩展方法(用于SimpleTrigger特定的属性)构建。

在特定的时间内建立触发器,无需重复,代码如下:

   /// <summary>
        /// 创建SimpleTrigger触发器(简单触发器)
        /// </summary>
        /// <param name="sysSchedule"></param>
        /// <param name="starRunTime"></param>
        /// <param name="endRunTime"></param>
        /// <returns></returns>
        private ITrigger CreateSimpleTrigger(SysSchedule sysSchedule)
        {
            if(sysSchedule.RunTimes>0)
            {
                ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
                .StartAt(sysSchedule.BeginTime.Value)
                .EndAt(sysSchedule.EndTime.Value)
                .WithSimpleSchedule(x =>
                x.WithIntervalInSeconds(sysSchedule.IntervalSecond)
                .WithRepeatCount(sysSchedule.RunTimes)).ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup).Build();
                return trigger;
            }
            else
            {
                ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
                .StartAt(sysSchedule.BeginTime.Value)
                .EndAt(sysSchedule.EndTime.Value)
                .WithSimpleSchedule(x =>
                x.WithIntervalInSeconds(sysSchedule.IntervalSecond)
                .RepeatForever()).ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup).Build();
                return trigger;
            }
            // 触发作业立即运行,然后每10秒重复一次,无限循环
            
        }

因此简单的任务调度使用SimpleTrigger完全够用,如果SimpleTrigger还是不能满足您的需求请往下看。

2、CronTrigger触发器

如果你需要一个基于类似日历的概念而不是精确指定的SimpleTrigger时间间隔的工作调度计划,CronTriggers通常比SimpleTrigger更有用。

使用CronTrigger,您可以在每周一,周三的上午9点至上午10点之间指定开始时间表,例如“每星期五中午”或“每个工作日和上午9点30分”,或者“每5分钟”和星期五”。

即使如此,就像SimpleTrigger一样,CronTrigger有一个startTime,它指定了时间表的生效时间,还有一个(可选的)endTime,用于指定应该停止时间表的时间。

这里不在详细介绍Cron

Cron表达式在线生成器:http://cron.qqe2.com/

Cron表达式详细介绍:https://www.jianshu.com/p/e9ce1a7e1ed1

   /// <summary>
        /// 创建类型Cron的触发器
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        private ITrigger CreateCronTrigger(SysSchedule sysSchedule)
        {
            // 作业触发器
            return TriggerBuilder.Create()
                   .WithIdentity(sysSchedule.Id.ToString(), sysSchedule.JobGroup)
                   .StartAt(sysSchedule.BeginTime.Value)//开始时间
                   .EndAt(sysSchedule.EndTime.Value)//结束数据
                   .WithCronSchedule(sysSchedule.Cron)//指定cron表达式
                   .ForJob(sysSchedule.Id.ToString(), sysSchedule.JobGroup)//作业名称
                   .Build();
        }

三、在Uwl.Admin.Core配置使用方法

   1、在Uwl.ScheduledTask.Job类库下面新建一个类继承于JobBase和IJob接口:

  

  2、在新建的类里面写一个方法,并且把这个方法通过实现的IJob的Execute方法传给JobBase基类:

  

  3、在新建的类里面写一个方法,并且把这个方法通过实现的IJob的Execute方法传给JobBase基类:

  在uwl.admin后台管理的定时任务模块添加一个新的任务,填写对应的名称,这里需要注意的是(DLL程序集是☞你的类库,任务所在类是指你的Job需要执行的Calss,这里有两种触发类型,一个是simple类型,一个是Cron类型可以根据自己的需要去设置对应的类型

  simple类型适合简单任务,开始时间和结束时间非必填,不填的话在你点击开始任务的时候就是默认执行,结束时间取的是最大时间)

  为什么要填程序集和类的名字呢,因为这里我是通过反射来获取程序集和类来进行执行那个Job的

  

  我们把这些配置完成之后点击启动任务就OK啦~~

  

  这里还有一点小问题……就是程序暂停运行了之后不会自动启动在执行的任务,后面我会慢慢修复,暂且各位大佬每次发布之后记得点击一下启动任务嗷~~~

  总结(很重要): Quartz.NET的3.0版本跟之前的版本api接口变化并不大。只是在3.0.7版本中添加了异步调用,并支持.net core。简单的任务调度使用官网中的实例即可满足需求,进行依赖注入的时候应当重写IJobFactory工厂,在IJobFactory工厂内重写         NewJob,ReturnJob方法;

  具体代码实现

   /// <summary>
        /// 注入反射获取依赖对象
        /// </summary>
        private readonly IServiceProvider _serviceProvider;
        public IOCJobFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        /// <summary>
        /// 实现接口Job
        /// </summary>
        /// <param name="bundle"></param>
        /// <param name="scheduler"></param>
        /// <returns></returns>
        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            try
            {

     这个位置需要重新创建_serviceProvider.CreateScope();容器,不然会提示找不到Job/还有一种情况是你也注入了但是Job无法执行,所以这个位置应当重新创建容器实例,
                var serviceScope = _serviceProvider.CreateScope();
                var job = serviceScope.ServiceProvider.GetService(bundle.JobDetail.JobType) as IJob;
                return job;
                //var job = _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob;
                //return job;

            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public void ReturnJob(IJob job)
        {
            var disposable = job as IDisposable;
            if(disposable!=null)
            {
                disposable.Dispose();
            }
            
        }

Uwl.Admin.Core开源框架(二) 使用QuartzNet的更多相关文章

  1. Uwl.Admin.Core开源框架(三) 使用RabbitMQ

    Uwl.Admin.Core中使用RabbitMQ消息队列: 本文负责讲解RabbitMQ的使用 Uwl.Admin.Core使用的技术有: *.Async和Await 异步编程 *.Reposito ...

  2. Magicodes.Admin.Core开源框架总体介绍

    框架说明 Magicodes.Admin.Core框架在ABP以及ASP.NET ZERO的基础上进行了封装和完善,目前基于.NET Core 2.0+(Framework版本),由于部分组件在.NE ...

  3. ERP开源框架 + 二次开发平台 介绍

    经历了多年软件开发,深受网络大侠们的资源共享才得以有所成绩, 本人主要是做企业ERP软件,一直有个感受,开发具体某个功能不难,但随着需求的增加,管理庞大的代码却成了最大的问题 而为企业管理所做的开发, ...

  4. .net Core开源框架NetModular记录

    NetModular 源码: https://github.com/iamoldli/NetModular 文档: https://nm.iamoldli.com/docs/guide/

  5. 使用微服务Blog.Core开源框架的一些坑

    1.使用SqlSuger组件时同一API无法自动切库 1.1 在生成Model时在类上加上特性 1.2 一个接口如果使用了多个数据库实例,会出现库找不到,需要使用ChangeDataBase切库 2. ...

  6. Uwl.Admin开源框架(二)

    Uwl.Admin开源框架基于QuartzNet定时任务模块的实现 Quartz.NET官网地址:https://www.quartz-scheduler.net/ Quartz.NET文档地址:ht ...

  7. Uwl.Admin开源框架(一)

    1.前言 作为一个忠实的软粉,一直期待微软出跨平台,一直在等待.Net Core,因为刚毕业对于.Net的很多东西不是很熟知,就开始了.Net Core的摸索,一路上坎坎坷坷,对于新技术一直很期待,就 ...

  8. c#实例化继承类,必须对被继承类的程序集做引用 .net core Redis分布式缓存客户端实现逻辑分析及示例demo 数据库笔记之索引和事务 centos 7下安装python 3.6笔记 你大波哥~ C#开源框架(转载) JSON C# Class Generator ---由json字符串生成C#实体类的工具

    c#实例化继承类,必须对被继承类的程序集做引用   0x00 问题 类型“Model.NewModel”在未被引用的程序集中定义.必须添加对程序集“Model, Version=1.0.0.0, Cu ...

  9. .NET Core开源Quartz.Net作业调度框架实战演练

    一.需求背景 人生苦短,我用.NET Core!作为一枚后端.NET开发人员,项目实践常遇到定时Job任务的工作,在Windows平台最容易想到的的思路Windows Service服务应用程序,而在 ...

随机推荐

  1. Color Models (RGB, CMY, HSI)

    目录 概 定义 RGB CMY CMYK HSI 相互的转换 RGB <=> CMY CMY <=> CMYK CMY > CMYK CMYK > CMY RGB ...

  2. JavaScript交互式网页设计 • 【第8章 jQuery动画与特效】

    全部章节   >>>> 本章目录 8.1 显示隐藏动画效果 8.1.1 show() 方法与hide() 方法 8.1.2 toggle()方法 8.1.3 实践练习 8.2 ...

  3. Log4j2基本使用入门

    1.Log4j2简介 Apache Log4j 2是日志框架Log4j的升级, 它比其前身Log4j 1.x提供了重要的改进, 并且参考了Logback中许多有用的改进, 同时修复了Logback的一 ...

  4. IntelliJ IDEA 2020.1.1 x64 Debug 断点调试模式详解

    前言 对于初入职场的萌新们来说,很多都还不会 Debug 断点模式.记得我刚写代码的时候,也是通过 System.out.println() 一行一行的把变量打印出来看.其实强大的编辑器已经帮我们做好 ...

  5. DGHV同态库

    DGHV DGHV全同态方案的实现 这是具有压缩公钥的DGHV的全同态加密方案的实现,参考文章: [1] J.S. Coron, D. Naccache and M. Tibouchi, " ...

  6. MYSQL 自定义序列函数

    代码如下: DROP TABLE SEQNUM; -- 创建序列表 CREATE TABLE SEQNUM( ID BIGINT ); -- 插入初识值 insert INTO SEQNUM valu ...

  7. 用软碟通UltraISO刻录Win 10 1909 到U盘,只有1个G左右,安装不了系统

    之前一直用软碟通刻录WIN10的ISO镜像到U盘.最近想到用最新版的WIN10 1909 来做一个U盘系统,刻录也成功了.就是安装系统的时候总报错,找了很久原因,终于发现刻录后占用U盘的空间只有1G左 ...

  8. 第10组 Alpha冲刺 (5/6)

    1.1基本情况 ·队名:今晚不睡觉 ·组长博客:https://www.cnblogs.com/cpandbb/p/13996848.html ·作业博客:https://edu.cnblogs.co ...

  9. hal 编码器做用户输入时捕获初值的设置

    uint16_t encoderDirection = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3); uint16_t encoderValue = __HA ...

  10. 关于Java注释报错的一个问题

    做作业时发现一个问题,注释会报错 主要代码如下: String str = "C:\\users\\Default.migrated"; str += "\\HelloW ...