转载

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

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

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

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

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

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

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

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

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

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

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

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

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

为什么要使用Quartz.Net

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

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

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

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

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

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

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

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

后端如何配置Quartz.Net

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

既然我们要动态配置到数据库里,那肯定就需要一个数据库表结构了,这个过程就是很简单的了,得益于我们有强大的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到数据库:

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

然后配置种子数据:

[

{

"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

}

]


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

(启动项目,自动SeedData)

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

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

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

建任务调度服务中心

当然,首先我们需要引用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

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

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

建Job工作

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

【项目升级】集成Quartz.Net 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);

// 开启job

var 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;

}


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

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

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

原文  http://mp.weixin.qq.com/s?__biz=MzAwNTMxMzg1MA==&mid=2654077830&idx=8&sn=c03aabc986bd66271fc01819e717d79e
正文到此结束
Loading...