前言
本来打算昨天都开始写这篇,就因为要把小团队的博客整理汇总,一看二哈的博客那么多,一个个复制粘贴肯定麻烦(其实是我自己觉得复制麻烦),所以穿插着写了个小爬虫,后续写差不多了就拿出来晾晾吧(py菜鸡水平)。
之前开发的时候,忽略了记录,等到想写点儿啥跟后台有关的东西的时候,还得一点点回忆,最近是因为同事给我说,"哎,每个月把数据给我统计下做个界面展示啊"。一想到每个月我要做次操作就头疼,咦,不对,这不就是写个定时任务就搞定了嘛。
Quartz
其实在选这个定时器的类库的时候,我在Hangfire两者间徘徊,后来是想到不管用什么方法什么工具都是次要的,主要看你怎么用,用到哪,图形界面是需要但不是必要,分秒级别的控制也都是看你自己业务需要,定时器就后台挂起运行就行了没必要让我看见,想操作了再说吧,就这样愉快的决定使用Quartz。
首先,依然是在我们Util的工程引入包。
引入完成后,在我们的入口Startup中添加实例的注册声明。
public IServiceProvider ConfigureServices(IServiceCollection services)
{
ServiceInjection.ConfigureRepository(services);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//任务调度
services.TryAddSingleton<ISchedulerFactory, StdSchedulerFactory>();
}
SchedulerFactory任务调度就好比一个公司的老大,Trigger就是一个项管,Job就是苦逼的码农,老大想要一天搞个app,就跟项管说一句,我要一天后要东西,这时候项管心里就有数了,一天后的那个时间,找到码农,直接剥夺他的代码执行,好了app出来了,苦逼的结束并不意味着真的结束,这老大一看可以啊,好了,以后每天我要一个成品app,如此循环往复,项管不厌其烦,码农换了又换(当然job不会)。
项管还会有多个,每个项管下面可不止一个码农。
像这样的情况可能有些夸张,但是类似的情况却真实存在。
ok,完了之后,我们来创建一个MyJob。
public class MyJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
return Task.Run(() =>
{
LogUtil.Debug("执行MyJob");
});
}
}
之后我们来写个简单的QuartzUtil。
public class QuartzUtil
{
private static ISchedulerFactory _schedulerFactory;
private static IScheduler _scheduler;
/// <summary>
/// 添加任务
/// </summary>
/// <param name="type">类</param>
/// <param name="jobKey">键</param>
/// <param name="trigger">触发器</param>
public static async Task Add(Type type, JobKey jobKey, ITrigger trigger = null)
{
Init();
_scheduler = await _schedulerFactory.GetScheduler();
await _scheduler.Start();
if (trigger == null)
{
trigger = TriggerBuilder.Create()
.WithIdentity("april.trigger")
.WithDescription("default")
.WithSimpleSchedule(x=>x.WithMisfireHandlingInstructionFireNow().WithRepeatCount(-1))
.Build();
}
var job = JobBuilder.Create(type)
.WithIdentity(jobKey)
.Build();
await _scheduler.ScheduleJob(job, trigger);
}
/// <summary>
/// 恢复任务
/// </summary>
/// <param name="jobKey">键</param>
public static async Task Resume(JobKey jobKey)
{
Init();
_scheduler = await _schedulerFactory.GetScheduler();
LogUtil.Debug($"恢复任务{jobKey.Group},{jobKey.Name}");
await _scheduler.ResumeJob(jobKey);
}
/// <summary>
/// 停止任务
/// </summary>
/// <param name="jobKey">键</param>
public static async Task Stop(JobKey jobKey)
{
Init();
_scheduler = await _schedulerFactory.GetScheduler();
LogUtil.Debug($"暂停任务{jobKey.Group},{jobKey.Name}");
await _scheduler.PauseJob(jobKey);
}
/// <summary>
/// 初始化
/// </summary>
private static void Init()
{
if (_schedulerFactory == null)
{
_schedulerFactory = AprilConfig.ServiceProvider.GetService<ISchedulerFactory>();
}
}
}
感谢jiulang指点,异步编程避免使用async void,因为这样会导致异常无法捕获。
触发器的使用,有很多种方式,可以使用简单的执行一次/多久执行一次/循环执行几次等等。
还有可以使用Cron表达式:
简单来说,corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份,举个例子,就像开头说的,让我每隔一个月执行一次统计,写法就是 0 0 0 1 * ?,当然这就有涉及到什么符号的问题了,