一、前言

近期项目中遇到一些需求,需要定时写入数据库,定时刷新缓存的问题,因此需要引入任务调度机制。

我的选择是使用 Quartz.Net,使用的版本是 3.2.4

这里强调一点:3.x的版本与2.x的版本使用方式有一定的差别,需要注意一下!!!

什么是Quartz.NET? Quartz.NET官方文档

Quartz.NET 是一个功能齐全的开源作业调度系统,可用于从最小的应用程序到大型企业系统。

二、Quartz.Net机制图

三、.Net Core中引入Quartz

新建.Net Core 类库项目命名为 MCronJob

创建完成后引入Quartz.Net

在Package Manager Console输入如下命令 安装Quartz包

Install-Package Quartz

由Quartz.Net关系图可知,我们需要JobFactory和实际任务类HelloJob

创建 CronJobFactory 类并实现  IJobFactory接口 ------------------任务工厂

public class CronJobFactory : IJobFactory
{
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
throw new NotImplementedException();
} public void ReturnJob(IJob job)
{
throw new NotImplementedException();
}
}

这里打个问号?NewJob和ReturnJob两个方法用来做什么?---------我是伏笔①

创建HelloJob类并实现  IJob接口 ---------------------------自定义的实际任务

public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
await Console.Out.WriteLineAsync($"{DateTime.Now:HH:mm:ss}--Hello World!");
}
}

有了任务工厂和任务,我们接下来实现具体的任务调度

新建SchedulerCenter类 ---------------------------------------------调度中心

public class SchedulerCenter
{
private readonly IJobFactory _jobFactory;
private readonly ISchedulerFactory _schedulerFactory;
private IScheduler _scheduler;
public SchedulerCenter(IJobFactory jobFactory, ISchedulerFactory schedulerFactory)
{
_jobFactory = jobFactory;
_schedulerFactory = schedulerFactory;
}
public async void StartScheduler()
{
//1、从工厂获取调度程序实例
_scheduler = await _schedulerFactory.GetScheduler(); // 替换默认工厂
//_scheduler.JobFactory = this._jobFactory; //2、打开调度器
await _scheduler.Start(); //3、定义作业详细信息并将其与HelloJob任务相关联
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("HelloJob", "HelloJobGroup")
.Build(); //4、配置触发条件:立即触发作业运行,然后每10秒重复一次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("HelloJob", "HelloJobGroup")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build(); //5、将作业与触发条件添加到调度实例并进行关联
await _scheduler.ScheduleJob(job, trigger);
}
public void StopScheduler()
{
_scheduler?.Shutdown(true).Wait(30000);
_scheduler = null;
}
}

SchedulerCenter 中定义了两个方法 StartScheduler(开启调度)和StopScheduler(停止调度)

StartScheduler方法中关于任务配置与官网相同,这里不再赘述 Quartz.Net官方配置

这里注掉了一段代码 替换默认工厂 ---------我是伏笔②

接下来我们要启动这个定时任务,在Startup类的ConfigureServices方法中进行注入

//注入调度中心
services.AddSingleton<SchedulerCenter>(); //注入Quartz任何工厂及调度工厂
services.AddSingleton<IJobFactory, CronJobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>(); //注入HelloJob
services.AddTransient<HelloJob>();

在Startup类的Configure方法中进行启动配置

//获取调度中心实例
var quartz = app.ApplicationServices.GetRequiredService<SchedulerCenter>(); lifetime.ApplicationStarted.Register(() =>
{
quartz.StartScheduler(); //项目启动后启动调度中心
}); lifetime.ApplicationStopped.Register(() =>
{
quartz.StopScheduler(); //项目停止后关闭调度中心
});

运行截图:

成功启动定时任务

其他方式启动定时任务: Net Core 官方使用方式

四、Job实现服务注入

HelloJob类中注入用户信息服务,输出用户信息,改动如下:

public class HelloJob : IJob
{
private readonly IUserInfoServices _userInfoServices;
public HelloJob(IUserInfoServices userInfoServices)
{
_userInfoServices = userInfoServices;
}
public async Task Execute(IJobExecutionContext context)
{
var userInfo = _userInfoServices.GetUserInfo();
await Console.Out.WriteLineAsync($"{DateTime.Now:HH:mm:ss}--姓名:{userInfo.UserName},年龄:{userInfo.Age},地址:{userInfo.Address}");
}
}

再次运行项目,等待了一段时间发现并没有我们想要的输出(这里折腾我好久。。。)

这时回看刚刚埋下的伏笔① ,IJobFactory接口中有两个方法,NewJob和ReturnJob,这俩个方法做什么用?

NewJob方法: 注解的大概意思是:当触发器触发时获取一个Job实例供调度器执行,那么如何获取的Job实例呢?

我们看下NewJob第一个参数 TriggerFiredBundle,转到TriggerFiredBundle定义,看其为我们提供了什么。

如上图所示:TriggerFiredBundle中可以获取到IJobDetail

IJobDetail中有JobType属性也就是我们定义的Job类型,我们要做的就是获取到Job实例

安装 Microsoft.AspNetCore.Antiforgery包

Install-Package Microsoft.AspNetCore.Antiforgery -Version 2.2.0

改动Job工厂类如下所示:

public class CronJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider; public CronJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
} public void ReturnJob(IJob job)
{
}
}

接着打开SchedulerCenter中 伏笔② 的注释:替换默认工厂

  // 替换默认工厂
_scheduler.JobFactory = this._jobFactory;

再次运行,用户服务成功调用

猜测:替换默认任务工厂后 IServiceProvider 取到的HelloJob是 ConfigureServices 中使用依赖注入的方式取到的实例,可取到UserInfoServices;

而未替换默认任务工厂取到的HelloJob并不能取到UserInfoServices,故HelloJob的Execute不能执行。

五、源码地址

gitee地址:https://gitee.com/sirius_machao/mweb-api

.Net Core 3.1浏览器后端服务(五) 引入定时任务Quartz.Net的更多相关文章

  1. .Net Core 3.1浏览器后端服务(一) Web API项目搭建

    一.前言 基于CefSharp开发的浏览器项目已有一段时间,考虑到后期数据维护需要Server端来管理,故开启新篇章搭建浏览器后端服务.该项目前期以梳理服务端知识为主,后期将配合CefSharp浏览器 ...

  2. .Net Core 3.1浏览器后端服务(三) Swagger引入与应用

    一.前言 前后端分离的软件开发方式已逐步成为互联网项目开发的业界标准,前后端分离带来了诸多好处的同时,也带来了一些弊端. 接口文档的维护就是其中之一,起初前后端约定文档规范,开发的很愉快,随着时间推移 ...

  3. .Net Core 3.1浏览器后端服务(四) 你眼中的依赖注入与我相同吗?

    一.前言 DI-Dependency Injection 依赖注入 IoC-Inversion of Control 控制反转 近几年这依赖注入. 控制反转已成为软件开发中不可或缺的一部分,那么该怎么 ...

  4. 容易被忽视的后端服务 chunked 性能问题

    容易被忽视的后端服务 chunked 性能问题 标签(空格分隔): springboot springmvc chunked 背景 spring boot 创建的默认 spring mvc 项目 集成 ...

  5. 快速新建简单的koa2后端服务

    既然前端工程化是基于NodeJS,那么选择NodeJs做前后端分离部署也是理所应当的.其实只需要实现静态资源和代理的话,用nginx才是最好的选择,用NodeJS是为了日后能进一步在服务端上实现自动构 ...

  6. [转]快速新建简单的koa2后端服务

    本文转自:https://blog.csdn.net/saucxs/article/details/83788259 既然前端工程化是基于NodeJS,那么选择NodeJs做前后端分离部署也是理所应当 ...

  7. Springboot & Mybatis 构建restful 服务五

    Springboot & Mybatis 构建restful 服务五 1 前置条件 成功执行完Springboot & Mybatis 构建restful 服务四 2 restful ...

  8. spring rest 容易被忽视的后端服务 chunked 性能问题

    spring boot 容易被忽视的后端服务 chunked 性能问题 标签(空格分隔): springboot springmvc chunked 作者:王清培(Plen wang) 沪江Java资 ...

  9. 微信后端服务架构及其过载控制系统DAGOR

    微信架构介绍   眼下的微信后端包含3000多个移动服务,包括即时消息.社交网络.移动支付和第三方授权.该平台每天收到的外部请求在10 ^10个至10^11个.每个这样的请求都会触发多得多的内部微服务 ...

随机推荐

  1. Web 实时通信方案 All In One

    Web 实时通信方案 All In One HTTP 轮询, 单向通信,开销大 HTTP 长轮询, 单向通信,开销较小 WebSocket,双向通信,开销小 (TCP 高延迟,保证数据完整性) Ser ...

  2. JSON-LD & SEO

    JSON-LD & SEO https://json-ld.org/ https://en.wikipedia.org/wiki/JSON-LD Google Search structure ...

  3. 小程序 in action

    小程序 in action https://github.com/xgqfrms/xcx-taro taro https://taro-docs.jd.com/taro/docs/README.htm ...

  4. Inspect Network Activity In Chrome DevTools

    Inspect Network Activity In Chrome DevTools https://developers.google.com/web/tools/chrome-devtools/ ...

  5. 人物传记STEPHEN LITAN:去中心化存储是Web3.0生态重要组成

    近期,NGK.IO的开发团队首席技术官STEPHEN LITAN分享了自己对去中心化储存的观点,以下为分享内容. 目前的存储方式主要是集中式存储,随着数据规模和复杂度的迅速增加,集中存储的数据对于系统 ...

  6. C++算法代码——纪念品分组[NOIP2007 普及组]

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=1099 https://www.luogu.com.cn/problem/P1094 ...

  7. Java如何保证文件落盘?

    本文转载自Java如何保证文件落盘? 导语 在之前的文章Linux/UNIX编程如何保证文件落盘中,我们聊了从应用到操作系统,我们要如何保证文件落盘,来确保掉电等故障不会导致数据丢失.JDK也封装了对 ...

  8. oracle impdp ORA-02304 invalid object identifier literal

    reference: https://webgeest.blogspot.com/2015/07/ora-39083-ora-02304-on-impdp-datapump.html     解决方法 ...

  9. CMD(命令提示符)的基本操作(文件夹)

    打开CMD窗口,接下来将介绍如何使用CMD来创建.删除.修改.查看文件夹(目录) ps:以下所有文件夹将统一写成目录 1.1 使用CMD创建空目录(为了更好的演示,本文皆以D盘为当前路径),命令如下: ...

  10. Java文件字节流

    //输出和输入流 package com.kangkang.IO; import com.sun.xml.internal.ws.util.xml.CDATA; import java.io.File ...