1 插件概述

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 作业执行的上下文

  1. 基类 JobExecutionContext

  2. 属性

    属性名 类型 说明
    JobId string 作业id
    TriggerId string 作业触发器
    JobDetail JobDetail 作业信息
    Trigger Trigger 作业触发器
    OccurrenceTime DateTime 作业计划触发时间
  3. 方法

    方法名 参数 说明
    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

    • 包含作业信息,作业触发器,作业处程序的基础信息
    • 包含SchedulerBuilderTriggerBuilder,任务和触发器的实例,可进行修改
  • 作业信息 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的更多相关文章

  1. SpringBoot系列九:SpringBoot服务整合(整合邮件服务、定时调度、Actuator监控)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 服务整合 2.背景 在进行项目开发的时候经常会遇见以下的几个问题:需要进行邮件发送.定时的任务调 ...

  2. java定时调度器解决方案分类及特性介绍

    什么是定时调度器? 我们知道程序的运行要么是由事件触发的,而这种事件的触发源头往往是用户通过ui交互操作层层传递过来的:但是我们知道还有另外一种由机器系统时间触发的程序运行场景.大家想想是否遇到或者听 ...

  3. Quartz定时调度框架

    Quartz定时调度框架CronTrigger时间配置格式说明 CronTrigger时间格式配置说明 CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年 ...

  4. Spring Quartz定时调度任务配置

    applicationContext-quartz.xml定时调度任务启动代码: <?xml version="1.0" encoding="UTF-8" ...

  5. 定时调度框架Quartz随笔

    最近项目中的定时批处理用到了quartz定时任务,在此记录下quartz的配置吧,一个小demo仅供参考,也方便自己今后复习! 下面直接来步骤吧! 一.首先,要搭起能让quartz正常运行的环境,至少 ...

  6. wordpress自动批量定时发布插件 DX-auto-publish

    DX-auto-publish是一款wordpress自动发布插件,方便实用. 该wordpress插件的主要功能如下: 1.能够自动批量定时发布wordpress站点的草稿文章,无需每篇文章都手动设 ...

  7. crontab 定时调度

    crontab -e */1 8-23 * * * /www/target/sh/myorder.sh & 0 1 * * * /www/target/php/sh/mymoney.sh &a ...

  8. java 多线程——quartz 定时调度的例子

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  9. java 多线程——一个定时调度的例子

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  10. linux定时调度器每秒运行一次

    linux操作系统最小粒度的定时调度器仅仅能调到分钟的级别,工作中有时需在到秒的调度,所以须要自己编写脚本来实现 #!/bin/bash while [ true ]; do /bin/sleep 1 ...

随机推荐

  1. Python基础之模块:7、项目开发流程和项目需求分析及软件开发目录

    一.项目开发流程 1.项目需求分析 明确项目具体功能: 明确到底要写什么东西,实现什么功能,在这个阶段的具体要询问项目经理和客户的需求 参与人员: 产品经理.架构师.开发经理 技术人员主要职责: 引导 ...

  2. JVM堆内存转储

    在发生内存溢出错误 java.lang.OutOfMemoryError 时, JVM自动执行堆内存转储,以方便事后进行排查和分析. JVM提供了一个命令行启动参数 HeapDumpOnOutOfMe ...

  3. 16.python中的回收机制

    python中的垃圾回收机制是以引用计数器为主,标记清除和分代回收为辅的 + 缓存机制 1.引用计数器 在python内部维护了一个名为refchain的环状双向链表,在python中创建的任何对象都 ...

  4. NC 使用Nginx实现https的反向代理

    summary: [通过Nginx实现NCC的https访问,并解决UClient应用的问题] 1 概述 通过Nginx 安装配置反向代理,实现NC.NCC的https访问. 本文以NCC2005为例 ...

  5. JUC学习笔记——共享模型之管程

    JUC学习笔记--共享模型之管程 在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的管程部分 我们会分为以下几部分进行介绍: 共享问题 共享问题解决方案 线程安全分析 Monitor ...

  6. 带你从入门到精通学习WireShark

    个人名片: 因为云计算成为了监控工程师‍ 个人博客:念舒_C.ying CSDN主页️:念舒_C.ying 带你从入门到精通学习WireShark 一.什么是WireShark? 二.WireShar ...

  7. 【Android】Configuration中的locale已过时

    Configuration中有很多属性的设置,在编译时提示错误说locale已过时这个是设置语言的 使用最新的方法如下 configuration.setLocale(locale);

  8. label studio 结合 MMDetection 实现数据集自动标记、模型迭代训练的闭环

    前言 一个 AI 方向的朋友因为标数据集发了篇 SCI 论文,看着他标了两个多月的数据集这么辛苦,就想着人工智能都能站在围棋巅峰了,难道不能动动小手为自己标数据吗?查了一下还真有一些能够满足此需求的框 ...

  9. 产生10个1-20以内的随机数,要求不能重复(集合)Java

    public class Demo{ //产生10个1-20以内的随机数,要求不能重复 public static void main(String[] args){ //新建集合存放随机数 Set& ...

  10. MySQL进阶实战2,那些年学过的事务

    @ 目录 一.MySQL服务器逻辑架构 二.并发控制 1.读写锁 2.锁粒度 3.表锁 4.行级锁 三.事务 1.原子性(atomicity) 2.一致性(consistency) 3.隔离性(iso ...