定时调度插件------Sundial
1 插件概述
- 开源链接:https://gitee.com/dotnetchina/Sundial
- 作者:百小僧
- 版本:2.5.6
2 使用方式
2.1 安装
- nuget :搜索Sundial或使用命令:Install-Package Sundial
- .NET CLI :dotnet add package Sundial
- 本地引用 :直接编译源码,引用
2.2 使用
2.2.1快速入门
自定义作业处理类
public class TestJob : IJob{
private readonly ILogger<TestJob> _logger;
public MyJob(ILogger<TestJob> logger){
_logger = logger;
}
public Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken){
_logger.LogInformation($"异步执行:{context}");
return Task.CompletedTask;
}
}
调用自定义类
//在Startup.cs中注册Schedule服务
Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddSchedule(options =>
{
options.AddJob<TestJob>(Triggers.PeriodSeconds(5)
, Triggers.Minutely());
});
})
.Build();
2.3 AddJob方法参数说明
重载一
一个或多个作业触发器
场景:作业相互独立,并行
参数:AddJob(params TriggerBuilder[] triggerBuilders)
参数说明:
- Triggers.Minutely() 每分钟执行一次
- Triggers.Period(1000) 每一秒执行一次
- Triggers.Cron("3,7,8 * * * * ?", CronStringFormat.WithSeconds)) 每分钟第 3/7/8 秒
- 参数为数组,因此可以包含多个触发器
举例
// 每5秒和每一分钟执行一次并行的作业
options.AddJob<MyJob>(Triggers.PeriodSeconds(5),Triggers.Minutely());
重载二
并发执行一个或多个作业触发器
场景:作业串行,同一时间只有一个作业
参数:AddJob(bool concurrent, params TriggerBuilder[] triggerBuilders),默认为并行
举例
//并行方式,每秒都会执行,不管上一个作业是否完成
options.AddJob<TestJob>(concurrent: true, Triggers.Secondly());
//串行方式,上一个任务完成才会执行,不一定每秒执行一次
options.AddJob<TestJob>(concurrent: false, Triggers.Secondly());
重载三
指定作业id的一个或多个作业触发器,默认系统会自动生成
场景:根据作业id进行业务处理,并行
参数:AddJob(string jobId, params TriggerBuilder[] triggerBuilders)
举例
// 定义一个叫job的作业,同一时间可能存在多个名为job的作业
options.AddJob<TestJob>("job", Triggers.Secondly());
重载四
指定作业id的一个或多个作业触发器且可以设置为串行
场景:根据作业id进行业务处理,串行
参数:AddJob(string jobId, bool concurrent, params TriggerBuilder[] triggerBuilders)
举例:
// 定义一个叫job的作业,串行,同一时间只有一个名为job的作业
options.AddJob<TestJob>("job", false, Triggers.Secondly());
2.4 JobExecutingContext 作业执行的上下文
基类 JobExecutionContext
属性
属性名 类型 说明 JobId string 作业id TriggerId string 作业触发器 JobDetail JobDetail 作业信息 Trigger Trigger 作业触发器 OccurrenceTime DateTime 作业计划触发时间 方法
方法名 参数 说明 ConvertToJSON(NamingConventions naming = NamingConventions.CamelCase) NamingConventions命名转换器 输出完整作业 的JSON ToString() 无 输出作业信息+触发器+计划触发事件+下次执行时间/触发器状态
2.3 作者的文档很全
[参见作者帮助文档](https://furion.baiqian.ltd/docs/job/#2613-%E4%BD%9C%E4%B8%9A%E4%BF%A1%E6%81%AF-jobdetail-%E5%8F%8A%E6%9E%84%E5%BB%BA%E5%99%A8)
3 关于调度器的通用理念
3.1 个人对调度器的理解
进行作业调度,首先要有一个或者多个作业(Job——英文名直译为工作/任务),一般是一个个独立的业务,例如车间通过某个零件使用率来判断是否需要向库房提报备件计划。
那什么时候执行这个任务呢?这就需要一个或者多个触发器(Trigger)来明确什么时候执行作业,触发器可以是一次性的,也可能是通过cron来定时。这样就形成了一个最基本的调度。
3.2 Sundial
作业计划 Scheduler
- 包含作业信息,作业触发器,作业处程序的基础信息
- 包含
SchedulerBuilder和TriggerBuilder,任务和触发器的实例,可进行修改
作业信息 JobDetail
通过JobDetail来进行初始化设置,只读类型不可更改
JobBuilder为运行时的JobDetial的类型,可直接修改运行时JobDetail数据
作业调度模块可提供多种方式创建JobBuilder对象
通过Create静态方法创建
// 根据作业 Id 创建
var jobBuilder = JobBuilder.Create("job1");
// 根据 IJob 实现类类型创建
var jobBuilder = JobBuilder.Create<MyJob>();
// 根据程序集名称和类型完全限定名(FullName)创建
var jobBuilder = JobBuilder.Create("YourProject", "YourProject.MyJob");
// 根据 Type 类型创建
var jobBuilder = JobBuilder.Create(typeof(MyJob));
// 通过委托创造动态作业
var jobBuilder = JoBuilder.Create((serviceProvider, context, stoppingToken) =>
{
serviceProvider.GetLogger().LogInformation($"{context}");
return Task.CompletedTask;
});
通过JobDetail类型创建
var jobBuilder = JobBuilder.From(jobDetail);
//也可以通过以下方式
var jobBuilder = jobDetail.GetBuilder();
通过LoadForm实例填充当前的JobBuilder
// 会覆盖所有相同的值
jobBuilder.LoadFrom(new
{
Description = "我是描述",
Concurrent = false
});
// 支持多个填充,还可以配置跳过 null 值覆盖
jobBuilder.LoadFrom(new
{
Description = "我是另外一个描述",
Concurrent = false,
IncludeAnnotations = default(object) // 会跳过赋值
}, ignoreNullValue: true);
// 支持忽略特定属性名映射
jobBuilder.LoadFrom(new
{
Description = "我是另外一个描述",
Concurrent = false,
IncludeAnnotations = default(object) // 会跳过赋值
}, ignorePropertyNames: new[]{ "description" });
// 支持字典类型
jobBuilder.LoadFrom(new Dictionary<string, object>
{
{"Description", "这是新的描述" },
{"include_annotations", false },
{"updatedTime", DateTime.Now }
});
通过注解进行赋值
[JobDetail("jobId")] // 仅作业 Id
[JobDetail("jobId", "这是一段描述")] // 描述
[JobDetail("jobId", false)] // 串行
[JobDetail("jobId", false, "这是一段描述")] // 串行 + 描述
[JobDetail("jobId", Concurrent = false, Description = "这是一段描述")]
public class MyJob : IJob
{
// ....
}
通过JSON字符串创建
var jobBuilder = JobBuilder.From(@"{
""jobId"": ""job1"",
""groupName"": null,
""jobType"": ""MyJob"",
""assemblyName"": ""ConsoleApp13"",
""description"": null,
""concurrent"": true,
""includeAnnotations"": false,
""properties"": ""{}"",
""updatedTime"": null
}");
作业触发器Trigger
Trigger在初始化时使用,运行时只读。
TriggerBuilder为运行时的实例,可修改监听
创建
TriggerStatus通过TriggerBuilder.Create进行创建
自定义作业触发器
继承
Trigger并重写GetNextOccurrence方法即可public class CustomTrigger : Trigger
{
public override DateTime GetNextOccurrence(DateTime startAt)
{
return startAt.AddSeconds(2);
}
}
调用CustomTrigger触发器
services.AddSchedule(options =>
{
//TriggerBuilder.Create 或 Triggers.Create都可以
options.AddJob<MyJob>(Triggers.Create<CustomTrigger>());
});
通过Tirgger类型创建(运行时更新作业触发器)
//通过tigger获得运行的triggerBuilder
var triggerBuilder = TriggerBuilder.From(trigger);
//直接get
triggerBuilder = trigger.GetBuilder();
作业处理程序IJob
作业处理类型注册模式,默认为单例模式,非单例模式,可通过
IServiceProvder创建// 瞬时的非单例模式,执行完毕即销毁
public class MyJob : IJob
{
private readonly ILogger<MyJob> _logger;
private readonly IConfiguration _configuration;
//当前的服务环境
private readonly IServiceProvider _serviceProvider; public MyJob(ILogger<MyJob> logger, IConfiguration configuration, IServiceProvider serviceProvider)
{
_logger = logger;
_configuration = configuration;
_serviceProvider = serviceProvider;
} public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
//创建不同的环境对象
using var serviceScope = _serviceProvider.CreateScope();
//在另一个环境对象中进行业务操作
var repository = serviceScope.ServiceProvider.GetService<IRepository<User>>();
_logger.LogInformation($"{context} {_configuration["key"]}");
await Task.CompletedTask;
}
} // 在该Job中有效的非单例注册模式
public class MyJob : IJob, IDisposable
{
private readonly ILogger<MyJob> _logger;
private readonly IConfiguration _configuration;
private readonly IServiceScope _serviceScope; public MyJob(ILogger<MyJob> logger
, IConfiguration configuration
, IServiceProvider serviceProvider)
{
_logger = logger;
_configuration = configuration;
_serviceScope = serviceProvider.CreateScope();
} public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
var repository = _serviceScope.ServiceProvider.GetService<IRepository<User>>();
var user = await repository.GetAsync(1); _logger.LogInformation($"{context} {_configuration["key"]}");
await Task.CompletedTask;
} public void Dispose()
{
_serviceScope?.Dispose();
}
}
作业监视器 IJobMonitor
可通过serviceProvider.GetService()获得一个IJobMonitor
也可自定义一个监视器
public class YourJobMonitor : IJobMonitor
{
private readonly ILogger<YourJobMonitor> _logger;
public YourJobMonitor(ILogger<YourJobMonitor> logger)
{
_logger = logger;
}
public Task OnExecutingAsync(JobExecutingContext context, CancellationToken stoppingToken)
{
_logger.LogInformation("执行之前:{context}", context);
return Task.CompletedTask;
}
public Task OnExecutedAsync(JobExecutedContext context, CancellationToken stoppingToken)
{
_logger.LogInformation("执行之后:{context}", context); if (context.Exception != null)
{
_logger.LogError(context.Exception, "执行出错啦:{context}", context);
}
return Task.CompletedTask;
}
} //在服务中注册
services.AddSchedule(options =>
{
// 添加作业执行监视器
options.AddMonitor<YourJobMonitor>();
});
作业执行器 IJobExecutor
当任务出现异常时-超时,异常,熔断,可通过作业执行器来定义执行策略
public class YourJobExecutor : IJobExecutor
{
private readonly ILogger<YourJobExecutor> _logger;
public YourJobExecutor(ILogger<YourJobExecutor> logger)
{
_logger = logger;
}
//jobHandler 当前实例的句柄
public async Task ExecuteAsync(JobExecutingContext context, IJob jobHandler, CancellationToken stoppingToken)
{
// 实现失败重试策略,如失败重试 3 次
await Retry.InvokeAsync(async () =>
{
await jobHandler.ExecuteAsync(context, stoppingToken);
}, 3, 1000
// 每次重试输出日志
, retryAction: (total, times) =>
{
_logger.LogWarning("Retrying {current}/{times} times for {context}", times, total, context);
});
}
} //在服务中注册
services.AddSchedule(options =>
{
// 添加作业执行器
options.AddExecutor<YourJobExecutor>();
});
定时调度插件------Sundial的更多相关文章
- SpringBoot系列九:SpringBoot服务整合(整合邮件服务、定时调度、Actuator监控)
声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 服务整合 2.背景 在进行项目开发的时候经常会遇见以下的几个问题:需要进行邮件发送.定时的任务调 ...
- java定时调度器解决方案分类及特性介绍
什么是定时调度器? 我们知道程序的运行要么是由事件触发的,而这种事件的触发源头往往是用户通过ui交互操作层层传递过来的:但是我们知道还有另外一种由机器系统时间触发的程序运行场景.大家想想是否遇到或者听 ...
- Quartz定时调度框架
Quartz定时调度框架CronTrigger时间配置格式说明 CronTrigger时间格式配置说明 CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年 ...
- Spring Quartz定时调度任务配置
applicationContext-quartz.xml定时调度任务启动代码: <?xml version="1.0" encoding="UTF-8" ...
- 定时调度框架Quartz随笔
最近项目中的定时批处理用到了quartz定时任务,在此记录下quartz的配置吧,一个小demo仅供参考,也方便自己今后复习! 下面直接来步骤吧! 一.首先,要搭起能让quartz正常运行的环境,至少 ...
- wordpress自动批量定时发布插件 DX-auto-publish
DX-auto-publish是一款wordpress自动发布插件,方便实用. 该wordpress插件的主要功能如下: 1.能够自动批量定时发布wordpress站点的草稿文章,无需每篇文章都手动设 ...
- crontab 定时调度
crontab -e */1 8-23 * * * /www/target/sh/myorder.sh & 0 1 * * * /www/target/php/sh/mymoney.sh &a ...
- java 多线程——quartz 定时调度的例子
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- java 多线程——一个定时调度的例子
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- linux定时调度器每秒运行一次
linux操作系统最小粒度的定时调度器仅仅能调到分钟的级别,工作中有时需在到秒的调度,所以须要自己编写脚本来实现 #!/bin/bash while [ true ]; do /bin/sleep 1 ...
随机推荐
- scrapy出现SSL问题 如何解决? <twisted.python.failure.Failure OpenSSL.SSL.Error: [('SSL routines', '', 'unsafe legacy renegotiation disabled')]>
问题:<twisted.python.failure.Failure OpenSSL.SSL.Error: [('SSL routines', '', 'unsafe legacy renego ...
- FHE学习笔记 #2 多项式环
https://en.wikipedia.org/wiki/Polynomial_ring https://zhuanlan.zhihu.com/p/419266064 这篇知乎文章讲的比较透彻,但是 ...
- Jmeter——请求响应内容乱码解决办法
前段时间,换过一次设备,重新下载了Jmeter.有一次在编写脚本时,响应内容中的中文一直显示乱码. 遇到乱码不要慌,肯定是有办法来解决的.具体解决办法,可以参考之前的博文,Jmeter--BeanSh ...
- Java项目有可能做到所有的代码逻辑均可热部署吗?
前言 首先我们明确下什么叫做热部署,热部署是在不重启java虚拟机的前提下,自动更新class的行为,从而更新整个运行时的逻辑. 在java开发领域,热部署一直是一个难以解决的问题,java虚拟机理论 ...
- Linux Polkit本地权限提升漏洞(CVE-2021-4034)
Linux Polkit本地权限提升漏洞(CVE-2021-4034) 免责声明: 漏洞描述 影响范围 漏洞检测 漏洞复现 修复建议 免责声明: 发现这个漏洞被各大预警平台刷屏了,目前主流Linux系 ...
- SpringBoot使用@Async的总结!
一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度. 之前有写过一篇文章叫做: 异步编程利器:CompletableFuture 在实际工作中也更加推荐使用CompletableFuture ...
- 这可能是最全的SpringBoot3新版本变化了!
11月24号,Spring Boot 3.0 发布了第一个正式的 GA 版本,一起看看新版本到底有哪些变化. 2.7版本升级指南 官方提供了一个从 2.7 版本升级到 3.0 的指南:https:// ...
- Excel二维码图片生成器
Excel二维码图片生成器 它可以将excel文件的数据,每行数据生成一张二维码图片,并保存到电脑.软件无需安装,解压后即可直接使用,无需联网,操作简便快捷. 软件下载地址:点此下载 步骤1:导入事先 ...
- JavaEE Day14 Servlet&HTTP&Request
今日内容 1.Servlet 2.HTTP协议 3.Request 一.Servlet 1.概念 2.步骤 3.执行原理 4.生命周期 5.Servlet 3.0注解配置 6.Servlet体系结构 ...
- 笔试面试--Java基础知识
一.基本概念 1.Java的优点 纯面向对象 平台无关性,"一次编译,到处运行(JVM上)",跨平台,可移植性 丰富类库:多线程.网络通信.垃圾回收 安全性(数组边界检测.byte ...