.Net Core 3.1浏览器后端服务(五) 引入定时任务Quartz.Net

1、前言

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

个人选择是使用 Quartz.Net,使用的版本是 3.2.4git

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

什么是Quartz.NET? Quartz.NET官方文档数据库

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

2、Quartz.Net机制图

3、.Net Core中引入Quartz

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

建立完成后引入Quartz.Netapp

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

Install-Package Quartz

 

 

 由Quartz.Net关系图可知,咱们须要JobFactory和实际任务类HelloJobide

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

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()
    {
        //一、从工厂获取调度程序实例
        _scheduler = await _schedulerFactory.GetScheduler();

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

        //二、打开调度器
        await _scheduler.Start();

        //三、定义做业详细信息并将其与HelloJob任务相关联
        IJobDetail job = JobBuilder.Create<HelloJob>()
            .WithIdentity("HelloJob", "HelloJobGroup")
            .Build();

        //四、配置触发条件:当即触发做业运行,而后每10秒重复一次
        ITrigger trigger = TriggerBuilder.Create()
            .WithIdentity("HelloJob", "HelloJobGroup")
            .StartNow()
            .WithSimpleSchedule(x => x
                .WithIntervalInSeconds(10)
                .RepeatForever())
            .Build();

        //五、将做业与触发条件添加到调度实例并进行关联
        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 官方使用方式

4、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不能执行。

5、源码地址

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

相关文章
相关标签/搜索