winform 框架_【壹起学】1:Uwl.Admin开源框架基于QuartzNet的实现

【壹起学】系列旨在向广大小伙伴推荐优秀开源框架,如果你有比较好的成型的NetCore 开源作品,欢迎给我联系,我们一起学!

本期项目地址:https://github.com/GeorGeWzw/Uwl.Admin.Core

37d3ac9d52a4b91f1eb2bab6f74b9a13.gifMerry Christmas 37d3ac9d52a4b91f1eb2bab6f74b9a13.gif

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

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

Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz 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也仍然有效

  • 增加了SQLServer内存优化表和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项目看
        ///         /// 开启任务调度        ///         ///         public async TaskStartScheduleAsync()        {            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()                    .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)            //{            //    //写入日志性能监控表和执行是否出错            //}        }    }}

执行效果:83f40c0c5c511b391c0828e9fab67ec6.png

二、触发器类型

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

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

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

        ///         /// 创建SimpleTrigger触发器(简单触发器)        ///         ///         ///         ///         ///         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

       ///         /// 创建类型Cron的触发器        ///         ///         ///         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接口:

  b8fa2b879b7cc455cfb27fc8bf718c3d.png

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

  976434409edea7ccee1a890c94d9a6ba.png

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

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

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

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

  e571fb728c747d6606ce86bb9fd0a0f6.png

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

  f93b3cfad3dbfdd639394c92fdee0633.png

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

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

具体代码实现
     ///         /// 注入反射获取依赖对象        ///         private readonly IServiceProvider _serviceProvider;        public IOCJobFactory(IServiceProvider serviceProvider)        {            _serviceProvider = serviceProvider;        }        ///         /// 实现接口Job        ///         ///         ///         ///         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();            }                    }

?点击查看原文

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值