【项目升级】集成Quartz.Net Job实现(一)

这两天的新闻也是越来越多了,不仅Github接手了NPM,还有.NET 5也要新鲜出炉了(11月正式发布),当然还有MVP峰会也正在如火如荼的展开,会有哪些好的东西被碰撞出来,也是很期待的。这些天我也简单的开始了学习之路,网路一直不好,直播也就不好展开,但是肯定会有的,应该过不了多久,所以暂时通过文字来讲解吧。

BCVP(也就是Blog.Core和Vue的全家桶)项目开源一年多,我也一直在开发和维护,目标呢,也一直致力于打造一个开箱即用的丰富小框架,目前的核心功能如下:

也算是完成了九层了吧,剩下的10%属于锦上添花的功能,一般小项目可能用不上,但是中型项目是必须要用的,今天的重点就是说说作业调度Quzrtz.net,目前已经集成到了项目里,为了不影响Master分支,目前代码在is4分支上,感兴趣的小伙伴可以自行PULL下来看看,目前的效果是这样的,下篇文章会集成到Blog.Admin项目中。

(任务调度展示,可持久化到数据库)

本文重点参考Kawhi代码,自己做了调整:

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

这个系列我打算写三篇文章和一篇视频的形式,文章分为后端、前端、原理三篇,视频就是总体串一下,今天就是第一篇,简单说说后端的配置和操作,不讲原理。

为什么要使用Quartz.Net

关于Quartz.Net的概念、内容和工作原理UML这都不说了,相信你如果看到了这个文章标题,并点进来了,应该知道这是干啥的,也应该知道他的应用场景——任务调度,白话就是通过一定的简单配置,定时去执行一些任务,多见于统计和同步操作。

这里简单的贴一下它Github的数据,就足可见受欢迎度:

(我一直认为,好的开源项目,要看Closed了多少Issue)

其实本来我的项目中已经有了一套任务执行程序,用的还是微软的自带的HostingService

用起来是特别简单,几乎不用配置,只需要创建一个Service,然后直接写逻辑就行了,它会随着我们的运行的项目一起执行,如果说你的任务调度很简单,就是定时跑一个小方法,我还是比较推荐这个的,当然,这个也是有很多问题,比如不能手动动态配置,不能手动控制任务的启动、暂停、重启等多个操作,所以,应群友的号召,我就把.net中用的较多的Quzrtz给集成到了项目里,当然还有一个Hangfire也很流行,我目前公司老的项目中是用的这个Hangfire,但是我感觉有些臃肿了,不太应景NetCore这么优雅的高效框架。

后端如何配置Quartz.Net

01

创建任务数据库表以及四层服务

既然我们要动态配置到数据库里,那肯定就需要一个数据库表结构了,这个过程就是很简单的了,得益于我们有强大的Seed功能,无论是是CodeFirst生成数据库表结构,还是根据表结构利用FrameSeed生成四层文件,都很简单。

首先是创建实体类,然后生成到数据库中,我已经配置好了:

   /// <summary>/// 任务计划表/// </summary>public class TasksQz : RootEntity{/// <summary>/// 任务名称/// </summary>[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]public string Name { get; set; }/// <summary>/// 任务分组/// </summary>[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]public string JobGroup { get; set; }/// <summary>/// 任务运行时间表达式/// </summary>[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]public string Cron { get; set; }/// <summary>/// 任务所在DLL对应的程序集名称/// </summary>[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]public string AssemblyName { get; set; }/// <summary>/// 任务所在类/// </summary>[SugarColumn(ColumnDataType = "nvarchar", Length = 200, IsNullable = true)]public string ClassName { get; set; }/// <summary>/// 任务描述/// </summary>public string Remark { get; set; }/// <summary>/// 执行次数/// </summary>public int RunTimes { get; set; }/// <summary>/// 开始时间/// </summary>public DateTime? BeginTime { get; set; }/// <summary>/// 结束时间/// </summary>public DateTime? EndTime { get; set; }/// <summary>/// 触发器类型(0、simple 1、cron)/// </summary>public int TriggerType { get; set; }/// <summary>/// 执行间隔时间, 秒为单位/// </summary>public int IntervalSecond { get; set; }/// <summary>/// 是否启动/// </summary>public bool IsStart { get; set; } = false;/// <summary>/// 执行传参/// </summary>public string JobParams { get; set; }[SugarColumn(IsNullable = true)]public bool? IsDeleted { get; set; }/// <summary>/// 创建时间/// </summary>[SugarColumn(IsNullable = true)]public DateTime CreateTime { get; set; } = DateTime.Now;}

然后SeedData到数据库:

然后配置种子数据:

[{"Name": "博客管理","JobGroup": "博客测试组","Cron": "","AssemblyName": "Blog.Core.Tasks","ClassName": "Job_Blogs_Quartz","Remark": "","RunTimes": 0,"BeginTime": "","EndTime": "","TriggerType": 0,//0是simple模式,1的cron模式"IntervalSecond": 120,//2分钟执行一次"IsStart": true,"JobParams": "1","IsDeleted": false,"CreateTime": "\/Date(1546272000000+0800)\/","Id": 1}
]

(启动项目,自动SeedData)

生成到数据库后,然后我们就需要生成四层服务文件,因为我们的Blog.Core项目已经封装了代码生成器,还是两个,你可以用T4,也可以用DbFirstController.cs这个控制器方法,只需要FrameSeed.cs文件中,配置上表名就行了:

最后可以创建一个控制器,对这个表进行CURD操作,不赘述。核心要说的,还是我们的任务调度中心。

02

创建任务调度服务中心

当然,首先我们需要引用Nuget包:

// 在Blog.Core.Tasks 层安装
<PackageReference Include="Quartz" Version="3.0.7" />

新建QuartzNet文件夹,创建调度服务接口和实现类,具体的原理我会在第三篇简单说下:

namespace Blog.Core.Tasks
{/// <summary>/// 服务调度接口/// </summary>public interface ISchedulerCenter{/// <summary>/// 开启任务调度/// </summary>/// <returns></returns>Task<MessageModel<string>> StartScheduleAsync();/// <summary>/// 停止任务调度/// </summary>/// <returns></returns>Task<MessageModel<string>> StopScheduleAsync();/// <summary>/// 添加/// </summary>/// <param name="sysSchedule"></param>/// <returns></returns>Task<MessageModel<string>> AddScheduleJobAsync(TasksQz sysSchedule);/// <summary>/// 停止一个任务/// </summary>/// <param name="sysSchedule"></param>/// <returns></returns>Task<MessageModel<string>> StopScheduleJobAsync(TasksQz sysSchedule);/// <summary>/// 恢复一个任务/// </summary>/// <param name="sysSchedule"></param>/// <returns></returns>Task<MessageModel<string>> ResumeJob(TasksQz sysSchedule);}
}

主要就是利用IScheduler对Job进行处理,核心的逻辑和代码都在实现类类,今天暂时先不进行讲解,具体的可以查看SchedulerCenterServer.cs

配置好了服务以及调度中心,接下来就是创建一个个Job类了。

03

创建Job工作

顾名思义,我们要想实现任务调度,就需要创建很多个Job工作类,让调度中心自己根据相应的逻辑机制来去调度,我这里创建了一个简单的Job作为示例:

namespace Blog.Core.Tasks
{public class Job_Blogs_Quartz : JobBase, IJob{private readonly IBlogArticleServices _blogArticleServices;private readonly ITasksQzServices _tasksQzServices;public Job_Blogs_Quartz(IBlogArticleServices blogArticleServices, ITasksQzServices tasksQzServices){_blogArticleServices = blogArticleServices;_tasksQzServices = tasksQzServices;}public async Task Execute(IJobExecutionContext context){var executeLog = await ExecuteJob(context, async () => await Run(context));//var param = context.MergedJobDataMap;// 可以直接获取 JobDetail 的值var jobKey = context.JobDetail.Key;var jobId = jobKey.Name;// 也可以通过数据库配置,获取传递过来的参数JobDataMap data = context.JobDetail.JobDataMap;//int jobId = data.GetInt("JobParam");var model = await _tasksQzServices.QueryById(jobId);if (model != null){model.RunTimes += 1;model.Remark += $"{executeLog}<br />";await _tasksQzServices.Update(model);}}public async Task Run(IJobExecutionContext context){var list = await _blogArticleServices.Query();await Console.Out.WriteLineAsync("博客总数量" + list.Count.ToString());}}
}

通过接口调用

这个就很简单了,毕竟我们前后端分离,要通过接口的形式来对我们的任务进行调度,这里简单的列举一个就行了:

 /// <summary>/// 启动计划任务/// </summary>/// <param name="jobId"></param>/// <returns></returns>[HttpGet]public async Task<MessageModel<string>> StartJob(int jobId){var data = new MessageModel<string>();// 获取任务服务var model = await _tasksQzServices.QueryById(jobId);// 开启jobvar ResuleModel = await _schedulerCenter.AddScheduleJobAsync(model);if (ResuleModel.success){model.IsStart = true;data.success = await _tasksQzServices.Update(model);}if (data.success){data.msg = "启动成功";data.response = jobId.ObjToString();}return data;}

最后的最后,不要忘记把相应的服务和接口进行注册:

好啦,关于后端如何配置任务调度Quzrtz.Net,就暂时说到这里了,下篇简单说下如何在前端配置页面吧,这两天我先设计着。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevC++如何安装自定义头文件并使用

首先我们打开DevC&#xff0c;然后点击新建。 新建一个控制台应用程序 取一个喜欢的文件名。 然后会出现如下界面。 点击新建单元 将头文件源码放入 找到空白位置&#xff0c;右键&#xff0c;然后点关闭并保存 保存的文件名要为头文件的名字 使用这个头文件时&#xff0c;只…

论ORM之EFCore初篇(快速基于本地数据库实现数据操作)

欢迎大家阅读《朝夕Net社区技术专刊》第6期我们致力于.NetCore的推广和落地&#xff0c;为更好的帮助大家学习&#xff0c;方便分享干货&#xff0c;特创此刊&#xff01;很高兴你能成为忠实读者&#xff0c;文末福利不要错过哦&#xff01;前言&#xff1a;今天准备带大家一站…

C++变量的初始化问题及列表初始化

在C中&#xff0c;初始化是一个异常复杂的问题&#xff0c;很多人认为初始化是赋值的一种&#xff0c;事实上&#xff0c;初始化和赋值是两个完全不同的操作。 列表初始化 要定义一个名为haif的int变量并初始化为0&#xff0c;以下4条语句都可以做到。 int haif 0; int hai…

c++ set 遍历_47. Set 是如何工作的(3) 遍历顺序是如何确定的?

Set 是无序容器&#xff0c;它的插入顺序与迭代&#xff08;或者 print&#xff09;输出的顺序不保证与插入顺序一致&#xff0c;与 Dict 类似的问题&#xff0c;Set 的输出顺序是如何决定的呢&#xff1f;首先我们从 Set 的输出开始寻找蛛丝马迹&#xff0c;在 Dict 的研究中&…

跟着“土牛”学架构知识

这里的土牛是指abp的作者&#xff0c;土耳其人&#xff0c;简称“土牛”&#xff0c;前两天看了他分享的ppt&#xff0c;这里做个小笔记。架构分层图一&#xff08;abp作者&#xff09;图二&#xff08;clean架构&#xff09;图三&#xff08;在朋友圈看到的&#xff09;每种架…

《C++ Primer》2.6.1节练习

练习2.39&#xff1a; 在类体花括号后加一个分号就好了。 练习2.40&#xff1a; 代码如下&#xff1a; struct Sales_data{std::string bookNo;//书籍编号unsigned units_sold 0;//销售量double sellingprice 0.0;//零售价double saleprice 0.0//实售价double discount 0…

Cef mysql.exe_CEF3.2623使用记录:windows编译

CEF3.2623使用记录&#xff1a;windows编译1&#xff1a;cef3.2623下载地址2623是cef3最后一个支持xp系统的版本&#xff0c;且可以支持html的audio标签&#xff0c;可以用作对html音频的处理下载地址为 https://bitbucket.org/chromiumembedded/cef/branch/2623。下载win32版本…

Asp.Net Core 中IdentityServer4 授权流程及刷新Token

一、前言上面分享了IdentityServer4 两篇系列文章&#xff0c;核心主题主要是密码授权模式及自定义授权模式&#xff0c;但是仅仅是分享了这两种模式的使用&#xff0c;这篇文章进一步来分享IdentityServer4的授权流程及refreshtoken。系列文章目录(没看过的先看这几篇文章再来…

C++关于const限定符,这一篇足够!!!

C关于const限定符&#xff0c;这一篇足够&#xff01;&#xff01;!const限定符初始化和constconst引用初始化和对const的引用对const的引用可能引用一个并非const对象指针和constconst指针顶层constconst限定符 有时候我们希望定义这样一种变量&#xff0c;它的值不能被改变。…

liunx版mysql服务无法启动_linux环境下mysql无法启动

无论发现怎样的问题&#xff0c;首先查看err日志。问题一&#xff1a;查询err日志显示权限问题。分析&#xff1a;mysql原本是所属mysql用户&#xff0c;如果在root用户下启动就有可能出现问题。解决&#xff1a;(1)查看mysql的权限(2)发现有root权限&#xff0c;混乱了。所以先…

玩转控件:重写/重绘Dev中MessageBox弹窗控件

很久没有更新博客了&#xff0c;本想着直接发一篇《手撕ERP》系列&#xff0c;从控件重写、重绘&#xff0c;到框架搭建&#xff0c;再到部分模块实现业务的。但是每次动手的时候&#xff0c;都觉得难以下手。直接从数据库设计开始吧&#xff0c;模块设计还没定下来&#xff0c…

.NET Core开发实战(第26课:工程结构概览:定义应用分层及依赖关系)--学习笔记...

26 | 工程结构概览&#xff1a;定义应用分层及依赖关系从这一节开始进入微服务实战部分这一节主要讲解工程的结构和应用的分层在应用的分层这里定义了四个层次&#xff1a;1、领域模型层2、基础设施层3、应用层4、共享层可以通过代码来看一下源码链接&#xff1a;https://githu…

容器网络是如何影响Kubernetes中数据库性能的?

关于Kubernetes中的数据库&#xff0c;大家最关心的第一个问题是性能。由于这种担心的存在&#xff0c;许多使用Kubernetes进行生产应用程序工作的客户正在Kubernetes之外的裸机或VM上运行数据库。因此&#xff0c;我们致力于深入研究Kubernetes抽象层&#xff0c;确定值得测试…

mysql php状态函数_mysql_stat()查询MySQL服务器当前系统状态

mysql教程&#xff1a;mysql_stat()查询MySQL服务器当前系统状态 定义和用法 mysql_stat() 函数返回 MySQL 服务器的当前系统状态。 如果成功&#xff0c;则该函数返回状态。如果失败&#xff0c;则返回 false。 语法 mysql_stat(connection)参数 描述 connection 可mysql教程&…

聊聊面试的事(应聘方)

这里是Z哥的个人公众号每周五11&#xff1a;45 按时送达当然了&#xff0c;也会时不时加个餐&#xff5e;我的第「134」篇原创敬上原本春节长假之后会有不少人开始新的面试之旅。但是疫情的到来打乱了这个节奏&#xff0c;包括招聘方的计划。因此&#xff0c;在以往是金三银四的…

mysql边备份边导入么_MySQL 怎么导入导出操作

mysql 如何导入导出操作1、MySQL 如何导入导出个别需要数据记录&#xff1f;– 先导出数据所在的表结构&#xff1a;mysql> show create table CHARBASE into outfile “/db/mysql/RS.sql” ;– 将需要单独导出的内容存放在文本文件里&#xff0c;这里一定要注意存放的位置必…

Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(三)

在前面两篇文章中&#xff0c;我介绍了基于IdentityServer4的一个Identity Service的实现&#xff0c;并且实现了一个Weather API和基于Ocelot的API网关&#xff0c;然后实现了通过Ocelot API网关整合Identity Service做身份认证的API请求。今天&#xff0c;我们进入前端开发&a…

[蓝桥杯][算法提高VIP]因式分解

解题思路&#xff1a; 水题&#xff01;&#xff01;&#xff01; 代码如下&#xff1a; #include <iostream> using namespace std; const int N 100010; int p[N]; int k; bool vis[N];void init() {for (int i 2;i<N-1;i){if (!vis[i])p[k] i;for (int j 2*i…

win10 64位操作系统安装mysql_win10,64位操作系统安装mysql-8.0.16经验总结(图文详细,保证一次安装成功)...

机器配置&#xff1a;win10&#xff0c;64位&#xff1b;mysql-8.0.161.mysql下载首先在mysql下载链接下载安装包&#xff1a;点击 Download 按钮进入下载页面&#xff0c;点击下图中的 No thanks, just start my download. 就可立即下载&#xff1a;2.解压及配置文件下载完后&…

基于 Roslyn 实现一个简单的条件解析引擎

基于 Roslyn 实现一个简单的条件解析引擎Intro最近在做一个勋章的服务&#xff0c;我们想定义一些勋章的获取条件&#xff0c;满足条件之后就给用户颁发一个勋章&#xff0c;定义条件的时候会定义需要哪些参数&#xff0c;参数的类型&#xff0c;获取勋章的时候会提供所需要的参…