ASP.NET Core托管运行Quartz.NET作业调度详解
Quartz.NET这么NB的作业调度系统,不会还行?
今天介绍一下Quartz.NET的托管运行,官网传送门。
一、前言
Quartz.NET,按官网上的说法,是一款功能齐全的任务调度系统,从小型应用到大型企业级系统都能适用。在众多项目中,Quartz.NET以可靠、集群的方式,被用作在定时器上运行后台任务的一种方式。
Quartz.NET主要完成两个方面的内容:
- 基于时间计划的后台作业;
- 基于因时间计划的触发的任务运行。
ASP.NET Core本身对于通过托管服务运行后台任务就支持的很好。当ASP.NET启动托管服务时,应用程序启动,并在生命周期内在后台运行。通过创建Quartz.NET托管服务,可以使用标准的.Net Core托管服务,在后台运行任务。
Quartz.NET可以创建定时的任务,例如每十分钟运行一个任务。除此之外,Quartz.NET还可以通过Cron触发器,定义任务在特定的日子或特定的时间运行,例如每天凌晨两点执行一个任务。它还允许以集群的方式运行应用程序的多个实例,以便在任何时间确保只有一个实例运行给定的任务。
下面,就针对这些特性和功能,进行详细的说明。
为防止非授权转发,这儿给出本文的原文链接:https://www.cnblogs.com/tiger-wang/p/13861121.html
二、安装Quartz.NET
Quartz.NET提供了NuGet包,所以安装很简单:
% dotnet add package quartz
这是个司机就知道,不详说了。
看一下安装后的.csproj
文件内容:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="quartz" Version="3.2.2" />
</ItemGroup>
</Project>
三、通过IJob创建任务类
我们用个例子来说明 - 创建一个Demo
的实现。它将写入ILogger<>
。我们会使用Quartz.NET的接口IJob
来实现,并使用依赖注入将日志注入到构造函数中。
[DisallowConcurrentExecution]
public class DemoJob : IJob
{
private readonly ILogger<DemoJob> _logger;
public DemoJob(ILogger<DemoJob> logger)
{
_logger = logger;
}
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("Demo !");
return Task.CompletedTask;
}
}
在类的前面,我用了一个DisallowConcurrentExecution
属性。这个属性可以防止Quartz.NET同时运行相同的作业。
四、通过IJobFactory创建任务工厂
通常情况下,Quartz.NET会使用Activator.CreateInstance
来创建作业的实例。
在我们这个例子里,我们换一种方式。使用IJobFactory
实现,并与ASP.NET Core的依赖注入容器挂钩。
public class SingletonJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public SingletonJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job)
{
}
}
这个IJobFactory
的实现,在构造函数中引入IServiceProvider
,并实现接口。
接口中,最重要的是NewJob()
方法。这个方法需要返回Quartz.NET调度器请求的IJob
。在我们的例子中,我们直接委托给IServiceProvider
,并让DI容器找到所需的实例。
ReturnJob()
方法是调度程序返回和销毁IJobFactory
创建的作业的地方。不过,因为我们使用了IServiceProvider
,而它没有提供这样的处理。所以,从安全的角度,应该使用单例作业。
五、配置作业
在第三节中,我们创建了一个IJob
的实现。这个实现直接使用就可以。
但是,我们这儿要加点内容。我们把Quartz
的托管服务做成一个通用实现,来调度任意的作业。因此,我们创建一个简单的DTO,并使用它来定义一个给定作业类型的时间器调度:
public class JobSchedule
{
public JobSchedule(Type jobType, string cronExpression)
{
JobType = jobType;
CronExpression = cronExpression;
}
public Type JobType { get; }
public string CronExpression { get; }
}
在这个类中,JobType
是一个作业的类型,例如本例子中的DemoJob
。CronExpression
是一个Cron
的表达式。
Cron表达式允许复杂的计时器调度,所以可以设置规则,比如每个月的5号和20号,在早上8点到10点之间每半小时触发一次。
关于Quartz.NET
的Cron
表达式,可以在这儿查到。
注意:不同操作系统使用的Cron表达式有一定的区别,写表达式的时候一定要注意这一点。
然后,我们把作业添加到Startup.ConfigureServices()
中:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IJobFactory, SingletonJobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<DemoJob>();
services.AddSingleton(new JobSchedule(
jobType: typeof(DemoJob),
cronExpression: "0/5 * * * * ?")); // 每5秒运行一次
}
这段代码向DI添加了四个单例对象:
- SingletonJobFactory,第四节的类,用于创建作业实例;
- ISchedulerFactory的一个实现,是内置的StdSchedulerFactory,用于处理调度和管理作业;
- DemoJob作业本身;
- DemoJob的一个JobSchedule实例,该实例具有每5秒运行一次的Cron表达式。
现在,主要代码已经完成,就差Quartz
托管服务了。
六、创建Quartz托管服务
QuartzHostedService
是自己创建的Quartz
托管服务,继承于IHostedService
,用于设置Quartz
调度器,并在后台启动它。
先看一下完整的代码:
public class QuartzHostedService : IHostedService
{
private readonly ISchedulerFactory _schedulerFactory;
private readonly IJobFactory _jobFactory;
private readonly IEnumerable<JobSchedule> _jobSchedules;
public QuartzHostedService(ISchedulerFactory schedulerFactory, IJobFactory jobFactory, IEnumerable<JobSchedule> jobSchedules)
{
_schedulerFactory = schedulerFactory;
_jobSchedules = jobSchedules;
_jobFactory = jobFactory;
}
public IScheduler Scheduler { get; set; }
public async Task StartAsync(CancellationToken cancellationToken)
{
Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
Scheduler.JobFactory = _jobFactory;
foreach (var jobSchedule in _jobSchedules)
{
var job = CreateJob(jobSchedule);
var trigger = CreateTrigger(jobSchedule);
await Scheduler.ScheduleJob(job, trigger, cancellationToken);
}
await Scheduler.Start(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await Scheduler?.Shutdown(cancellationToken);
}
private ITrigger CreateTrigger(JobSchedule schedule)
{
return TriggerBuilder
.Create()
.WithIdentity($"{schedule.JobType.FullName}.trigger")
.WithCronSchedule(schedule.CronExpression)
.WithDescription(schedule.CronExpression)
.Build();
}
private IJobDetail CreateJob(JobSchedule schedule)
{
var jobType = schedule.JobType;
return JobBuilder
.Create(jobType)
.WithIdentity(jobType.FullName)
.WithDescription(jobType.Name)
.Build();
}
}
解释一下这段代码:
这段代码中,QuartzHostedService
有三个依赖项:Startup.ConfigureServices()
中注入的ISchedulerFactory
和IJobFactory
,以及一个IEnumerable
。在第五节的代码中,我们只向DI添加了一个JobSchedule
,就是DemoJob
。我们也可以添加多个JobSchedule
,他们都会在这个IEnumerable
中被注入到托管服务中。
StartAsync
在应用程序启动时被调用,它是我们配置Quartz
的地方。我们首先创建IScheduler
的一个实例,为它分配一个属性供以后使用,并将调度程序的JobFactory
设置为注入的实例:
public async Task StartAsync(CancellationToken cancellationToken)
{
Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
Scheduler.JobFactory = _jobFactory;
//...
}
然后,循环注入的作业调度,并在类的最后使用CreateJob
和CreateTrigger
方法为每个作业创建一个IJobDetail
和ITrigger
。实际应用中如果有别的需要,也可以通过扩展JobSchedule
DTO来定制它。
最后,在调度了所有作业之后,调用Scheduler.Start()
来实际在后台启动Quartz.NET调度器。当应用程序关闭时,框架将调用StopAsync()
,此时可以调用Scheduler.Shutdown()
来安全地关闭调度程序进程。
全部完成后,我们启动QuartzHostedService
:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddHostedService<QuartzHostedService>();
}
运行程序,可以看到结果:
demo.DemoJob: Information: Demo !
info: demo.DemoJob[0]
Demo !
demo.DemoJob: Information: Demo !
info: demo.DemoJob[0]
Demo !
demo.DemoJob: Information: Demo !
info: demo.DemoJob[0]
Demo !
demo.DemoJob: Information: Demo !
info: demo.DemoJob[0]
Demo !
本文的代码,在https://github.com/humornif/Demo-Code/tree/master/0029/demo
微信公众号:老王Plus 扫描二维码,关注个人公众号,可以第一时间得到最新的个人文章和内容推送 本文版权归作者所有,转载请保留此声明和原文链接 |
ASP.NET Core托管运行Quartz.NET作业调度详解的更多相关文章
- ASP.NET Core MVC 源码学习:详解 Action 的激活
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- ASP.NET Core MVC 源码学习:详解 Action 的匹配
前言 在 上一篇 文章中,我们已经学习了 ASP.NET Core MVC 的启动流程,那么 MVC 在启动了之后,当请求到达过来的时候,它是怎么样处理的呢? 又是怎么样把我们的请求准确的传达到我们的 ...
- DevExpress ASP.NET Core Controls v18.2新功能详解
行业领先的.NET界面控件2018年第二次重大更新——DevExpress v18.2日前正式发布,本站将以连载的形式为大家介绍新版本新功能.本文将介绍了DevExpress ASP.NET Core ...
- Asp.Net Core 中IdentityServer4 实战之 Claim详解
一.前言 由于疫情原因,让我开始了以博客的方式来学习和分享技术(持续分享的过程也是自己学习成长的过程),同时也让更多的初学者学习到相关知识,如果我的文章中有分析不到位的地方,还请大家多多指教:以后我会 ...
- ASP.NET Core托管和部署Linux实操演练手册
一.课程介绍 ASP.NET Core 是一种全新的跨平台开源 .NET 框架,能够在 IIS.Nginx.Apache.Docker 上进行托管或在自己的进程中进行自托管. 作为一个.NET Web ...
- 【ASP.NET Core】运行原理之启动WebHost
ASP.NET Core运行原理之启动WebHost 本节将分析WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build ...
- 【ASP.NET Core】运行原理[3]:认证
本节将分析Authentication 源代码参考.NET Core 2.0.0 HttpAbstractions Security 目录 认证 AddAuthentication IAuthenti ...
- 【ASP.NET Core】运行原理(4):授权
本系列将分析ASP.NET Core运行原理 [ASP.NET Core]运行原理(1):创建WebHost [ASP.NET Core]运行原理(2):启动WebHost [ASP.NET Core ...
- ASP.NET CORE下运行CMD命令
ASP.NET CORE下运行CMD命令,用以前的ASP.NET 的命令System.Diagnostics.Process.Start("notepad");这样是可以运行出记事 ...
随机推荐
- Docker实战(2):主从库搭建
入门 基于Docker的Mysql主从复制搭建 首先安装docker 拉取mysql镜像:5.7版本 启动主从数据库容器 docker run -p 3339:3306 --name Maste -e ...
- mysql读写分离--一主多从,冗余存储
转载了https://blog.csdn.net/u013421629/article/details/78793966 https://blog.csdn.net/justdb/article/de ...
- java安全编码指南之:输入校验
目录 简介 在字符串标准化之后进行校验 注意不可信字符串的格式化 小心使用Runtime.exec() 正则表达式的匹配 简介 为了保证java程序的安全,任何外部用户的输入我们都认为是可能有恶意攻击 ...
- RDS、DDS 和 GaussDB 理不清?看这一篇足够了!
当前,华为云提供的数据库服务主要包括三大类:关系型数据库服务,非关系型数据库服务以及数据库工具服务.如下图所示: 关系型数据库和非关系型数据库均可分为开源和自研两大类.其中,自研数据库统一为Gauss ...
- 笨办法学Python3习题19
学习笔记记录一下 def cheese_and_crackers(cheese_count, boxes_of_crackers): print (f"You have {cheese_co ...
- 基于SpringBoot+SpringDataJpa后台管理
昨天朋友找我喝酒,说30岁了,比较焦虑,钱没赚到,整天被媳妇数落. 其实现在我们看到的不一定就事真实的情况,就算从高斯分布看,平平淡淡的人生才是大部分人的轨迹.当然抖音.知乎上的不能比,人均收入百万, ...
- spring Boot面试题(2020最新版)
概述 什么是 Spring Boot? Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式解决方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提 ...
- Centos-切换用户身份-su
su 切换用户身份 相关选项 - 加载相应用户下环境变量 -c 使用某个身份执行一个指令 -m 改变用户身份不改变环境变量 切换为超级用户 su - 普通用户切换为超级用户需要输入密码,超级用户 ...
- mysql5.7开启慢查询日志
环境:centos7 mysql版本:5.7.28 一.什么是慢查询 MySQL默认10s内没有响应SQL结果,则为慢查询 当然我们也可以修改这个默认时间 查看慢查询的时间 show variable ...
- 实验 6:OpenDaylight 实验——OpenDaylight 及 Postman 实现流表下发
一.实验目的 熟悉 Postman 的使用;熟悉如何使用 OpenDaylight 通过 Postman 下发流表. 二.实验任务 流表有软超时和硬超时的概念,分别对应流表中的 idle_timeou ...