在 worker service 中使用 quartz.net
source link: https://blog.zhuliang.ltd/2020/07/backend/using-quartz-in-worker-service.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
在 worker service 中使用 quartz.net
create: 2020-07-20 12:35:43 | update: 2020-07-20 12:35:43
本文总阅读量: 16 次
|
文章总字数: 839 字
|
阅读约需: 4 分钟
- 以下示例基于 Quartz.Net 3.0.7(在最新的 3.1-beta2 中已经包含了支持 Microsoft DI 的方法)
在 worker service 中,通过官网示例,会发现 quartz.net 并未生效,究其原因系 DI 未注入导致,原生 quartz.net(3.0.7)是通过 CreateInstance 来创建实例的,本文旨在解决在 Worker Service、Console 中使用 quartz.net 无效的问题。
项目结构如下:
JobSchedule.cs
用来配置 Job,如果需要更多配置,可以扩展该类。
public class JobSchedule
{
public JobSchedule(Type jobType, string cronExpression)
{
JobType = jobType;
CronExpression = cronExpression;
}
public Type JobType { get; }
public string CronExpression { get; }
}
SingletonJobFactory.cs
默认情况下,Quartz 是通过 Activator.CreateInstance 来创建实例的,这里因为要使用 IoC,所以这里需要自定义一个 IJobFactory 以来使用构造函数注入。
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) { }
}
- P.S.: 目前 Quartz.Net 的机制导致只能使用 Singleton 或者 Transient 类型来进行注入,否则无法保证 IJob 的实现是安全的。
QuartzHostedService.cs
宿主服务,以便可以在后台运行
public class QuartzHostedService : IHostedService
{
#region Implementation of IHostedService
private readonly ISchedulerFactory _schedulerFactory;
private readonly IJobFactory _jobFactory;
private readonly IEnumerable<JobSchedule> _jobSchedules;
public QuartzHostedService(
ISchedulerFactory schedulerFactory,
IJobFactory jobFactory,
IEnumerable<JobSchedule> jobSchedules //IEnumerable允许你注入多个Job
)
{
_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 static IJobDetail CreateJob(JobSchedule schedule)
{
var jobType = schedule.JobType;
return JobBuilder
.Create(jobType)
.WithIdentity(jobType.FullName)
.WithDescription(jobType.Name)
.Build();
}
private static ITrigger CreateTrigger(JobSchedule schedule)
{
return TriggerBuilder
.Create()
.WithIdentity($"{schedule.JobType.FullName}.trigger")
.WithCronSchedule(schedule.CronExpression)
.WithDescription(schedule.CronExpression)
.Build();
}
#endregion
}
配置:IoC
Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<IJobFactory, SingletonJobFactory>();
services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
// Jobs
services.AddSingleton<MyJob>();
services.AddSingleton<MyJob2>();
services.AddSingleton(new JobSchedule(
jobType: typeof(MyJob),
cronExpression: "0/5 * * * * ?")); // 每5s
//不同的规则可以单独建立
services.AddSingleton(new JobSchedule(
jobType: typeof(MyJob2),
cronExpression: "0/1 * * * * ?")); // 每1s
services.AddHostedService<QuartzHostedService>();
services.AddHostedService<Worker>();
});
}
Job 示例
[DisallowConcurrentExecution]
public class MyJob : IJob
{
private readonly ILogger<MyJob> _logger;
public MyJob(ILogger<MyJob> logger)
{
_logger = logger;
}
#region Implementation of IJob
/// <summary>
/// Called by the <see cref="T:Quartz.IScheduler" /> when a <see cref="T:Quartz.ITrigger" />
/// fires that is associated with the <see cref="T:Quartz.IJob" />.
/// </summary>
/// <remarks>
/// The implementation may wish to set a result object on the
/// JobExecutionContext before this method exits. The result itself
/// is meaningless to Quartz, but may be informative to
/// <see cref="T:Quartz.IJobListener" />s or
/// <see cref="T:Quartz.ITriggerListener" />s that are watching the job's
/// execution.
/// </remarks>
/// <param name="context">The execution context.</param>
public async Task Execute(IJobExecutionContext context)
{
await Task.Run(() =>
{
_logger.LogInformation($"I am MyJob,DetailGroup={context.JobDetail.Key.Group},DetailName={context.JobDetail.Key.Name}");
});
}
#endregion
}
特性说明:
[DisallowConcurrentExecution]:防止并行执行相同的 Job。
因为注入时只能使用 Singleton 或者 Transient,所以对于 Scoped 类型的 DI无法使用,如果硬要使用的话,可以通过如下方式进行:
public class MyJob : IJob
{
// Inject the DI provider
private readonly IServiceProvider _provider;
public MyJob( IServiceProvider provider)
{
_provider = provider;
}
public async Task Execute(IJobExecutionContext context)
{
await Task.Run(() =>
{
using(var scope = _provider.CreateScope())
{
// Scoped service
var service = scope.ServiceProvider.GetService<IScopedService>();
_logger.LogInformation("MyJob Scope Tips。");
}
});
}
}
Recommend
-
15
当我们在web开发中,常常会遇到这么一个需求,在后台执行某一项具体的任务,具体的说就是这些任务必须在后台定时执行。 Quartz.NET...
-
11
Quartz 概述 Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,它可以与 J2EE、 J2SE 应用程序相结合也可以单独使用。 Quartz 可以用来创建简单或为运行十个,百个,甚至是...
-
8
在 ASP.NET Core和Worker Service中使用Quartz.Net ...
-
9
Working Hard So You Don’t Have ToLet’s explore how to leverage the Worker Service template available with .NET Core to set up and run long-running processes across different environments. .NET Core’s Worker Service provides a newer tem...
-
5
基于.Net Core 5.0 Worker Service 的 Quart 服务 看过我之前博客的人应该都知道,我负...
-
8
上一篇文章中我们了解了 .NET Worker Service 的入门知识[1]
-
8
前面我们了解了 .NET Worker Service 的入门知识[1] 和
-
4
记Quartz中使用AutoFac依赖注入遇到的问题发布于 8 月 15 日 最近在做一个需求,就是在Job中捕捉异常,然后通过邮件或者消息的方式推送给指定人员,在需求实现...
-
1
例如需要在某年某月去将数据库的某个数据更新或者同步,又或者是每隔一段时间来执行一部分代码去调用接口,但是又不想人为的手动去执行 针对此类业务可以使用"定时调用任务",市面上有很多的定时调度任务框架,甚至你可以使用定时器来结合Windows服务做一个...
-
5
Use a .NET Worker Service to run background services 17th February 2022 ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK