当咱们在 web 开发中,经常会遇到这么一个需要,在后盾执行某一项具体的工作,具体的说就是这些工作必须在后盾定时执行。
Quartz.NET 是一个开源的 JAVA 移植版,它有着悠久的历史并且提供了弱小的 Cron 表达式,这篇咱们就来探讨如何在 ASP.NET Core 中应用 Quartz.NET 去执行一些后台任务。
装置 Quartz.NET
要想应用 Quartz.NET,你能够应用 Visual Studio 2019 中的 NuGet package manager
可视化界面进行装置,或者通过 NuGet package manager console
命令行输出如下命令:
Install-Package Quartz
Quartz.NET 中的 Job,triggers 和 Schedulers
Quartz.NET 里有三个十分重要的概念:工作,触发器 和 调度器,对应着 Job,Trigger 和 Schedulers,Job 示意一个你须要被执行的工作,工作中能够写上你的业务逻辑代码,Job 就是一个实现了 IJob 接口的子类,如下代码所示:
class Job : IJob
{public Task Execute(IJobExecutionContext context)
{throw new NotImplementedException();
}
}
Trigger 通常用于指定一个 job 是如何被调度的?什么意思呢?比如说:这个 job 是按天执行?还是按小时执行?还是按秒执行?值得注意的是因为反对了 Cron 表达式,还可能实现更加超级简单的调度逻辑。
Scheduler 通常依照你事后设置的调度规定将 job 丢给它的工作队列,并依照 trigger 规定轮询而后执行工作。
创立 Scheduler
在 Quartz.NET 中能够创立多个 Scheduler,但为了演示目标我就创立一个 Scheduler 啦,上面的代码展现了如何去创立 Scheduler。
var scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
一旦应用下面的代码创立好了 Scheduler,接下来就能够将其作为服务注入到 Asp.net Core 的 IOC 容器中,实现代码如下:
public void ConfigureServices(IServiceCollection services)
{var scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
services.AddSingleton(scheduler);
services.AddRazorPages();}
开启和进行 scheduler
为了不便实现 开启
和 进行
性能,我筹备封装一个 hosting service 类,做法就是从 IHostingService
接口派生出一个 CustomQuartzHostedService
类,残缺代码如下:
public class CustomQuartzHostedService : IHostedService
{
private readonly IScheduler _scheduler;
public CustomQuartzHostedService(IScheduler scheduler)
{_scheduler = scheduler;}
public async Task StartAsync(CancellationToken cancellationToken)
{await _scheduler?.Start(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{await _scheduler?.Shutdown(cancellationToken);
}
}
有了这个自定义类,接下来把这个类也注入到 servcies collection
中,实现代码如下:
public void ConfigureServices(IServiceCollection services)
{var scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
services.AddSingleton(scheduler);
services.AddHostedService<CustomQuartzHostedService>();
services.AddRazorPages();}
创立 job
正如之前说到的,job 是一个实现了 IJob 接口 并且实现了 Execute() 的类,这个 Execute() 办法接管一个 IJobExecutionContext
参数。
上面的代码片段展现了这个 Job 类蕴含了一个异步形式的 Execute() 办法,这个办法中蕴含的代码就是你须要执行的业务逻辑。
[DisallowConcurrentExecution]
public class NotificationJob : IJob
{
private readonly ILogger<NotificationJob> _logger;
public NotificationJob(ILogger<NotificationJob> logger)
{_logger = logger;}
public Task Execute(IJobExecutionContext context)
{_logger.LogInformation("Hello world!");
return Task.CompletedTask;
}
}
创立 job 工厂
如果要定义一个 Job 工厂,则必须要实现 IJobFactory 接口中的 NewJob() 和 ReturnJob() 办法,上面的代码片段展现了如何去 创立 和 返回 job 的 factory 类。
public class CustomQuartzJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public CustomQuartzJobFactory(IServiceProvider serviceProvider)
{_serviceProvider = serviceProvider;}
public IJob NewJob(TriggerFiredBundle triggerFiredBundle,
IScheduler scheduler)
{
var jobDetail = triggerFiredBundle.JobDetail;
return (IJob)_serviceProvider.GetService(jobDetail.JobType);
}
public void ReturnJob(IJob job) {}}
值得注意的是,这里我并没有实现 job 池,如果你想实现这个性能,你须要批改以下 NewJob() 办法 并且重写 ReturnJob() 办法。
创立 JobMetadata 存储你的 job 元数据
我筹备定义一个 JobMetadata 类去存储和 job 相关联的元数据,比如说:job 的 id,job 的 name 等等,上面的代码展现了如何定义这么一个类。
public class JobMetadata
{public Guid JobId { get; set;}
public Type JobType {get;}
public string JobName {get;}
public string CronExpression {get;}
public JobMetadata(Guid Id, Type jobType, string jobName,
string cronExpression)
{
JobId = Id;
JobType = jobType;
JobName = jobName;
CronExpression = cronExpression;
}
}
应用 hosted service 封装 Scheduler 的 start 和 stop
接下来,我须要丰盛一下 CustomQuartzHostedService 类,残缺的代码清单如下。
public class CustomQuartzHostedService : IHostedService
{
private readonly ISchedulerFactory schedulerFactory;
private readonly IJobFactory jobFactory;
private readonly JobMetadata jobMetadata;
public CustomQuartzHostedService(ISchedulerFactory schedulerFactory,JobMetadata jobMetadata,IJobFactory jobFactory)
{
this.schedulerFactory = schedulerFactory;
this.jobMetadata = jobMetadata;
this.jobFactory = jobFactory;
}
public IScheduler Scheduler {get; set;}
public async Task StartAsync(CancellationToken cancellationToken)
{Scheduler = await schedulerFactory.GetScheduler();
Scheduler.JobFactory = jobFactory;
var job = CreateJob(jobMetadata);
var trigger = CreateTrigger(jobMetadata);
await Scheduler.ScheduleJob(job, trigger, cancellationToken);
await Scheduler.Start(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{await Scheduler?.Shutdown(cancellationToken);
}
private ITrigger CreateTrigger(JobMetadata jobMetadata)
{return TriggerBuilder.Create()
.WithIdentity(jobMetadata.JobId.ToString())
.WithCronSchedule(jobMetadata.CronExpression)
.WithDescription($"{jobMetadata.JobName}")
.Build();}
private IJobDetail CreateJob(JobMetadata jobMetadata)
{
return JobBuilder
.Create(jobMetadata.JobType)
.WithIdentity(jobMetadata.JobId.ToString())
.WithDescription($"{jobMetadata.JobName}")
.Build();}
}
接下来再看一下 Startup.ConfigureServices
办法下的残缺代码。
public void ConfigureServices(IServiceCollection services)
{services.AddRazorPages();
services.AddSingleton<IJobFactory, CustomQuartzJobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<NotificationJob>();
services.AddSingleton(new JobMetadata(Guid.NewGuid(), typeof(NotificationJob),"Notification Job", "0/10 * * * * ?"));
services.AddHostedService<CustomQuartzHostedService>();}
这就是所有要做的事件,接下来运行应用程序,你会察看到 NotificationJob 的 Execute() 办法会每 10s 执行一次。
如何你的应用程序中须要有工作调用的性能,当初开始能够不须要应用 Timer 了,采纳弱小的 Quartz.NET 即可,而且还有一个???????? 的性能就是:你能够把 job 长久化到 SQL Server, PostgreSQL, SQLite 中,太强大了。
译文链接:https://www.infoworld.com/art…
更多高质量干货:参见我的 GitHub: dotnetfly