Springboot2.x + Clúster distribuido de cuarzo

Springboot2.x + Clúster distribuido de cuarzo

El entorno de producción es generalmente de alta disponibilidad de múltiples nodos. Springboot en sí tiene su propia función de tarea de sincronización, pero los requisitos de nuestro proyecto requieren que podamos agregar, eliminar, modificar y verificar tareas de sincronización. Entonces, considerando la introducción de Quartz, la introducción de Quartz requiere la consideración de clústeres distribuidos, por lo que este artículo está aquí.

Script de base de datos

La base de datos Quartz tiene 11 tablas, que admiten tanto Mysql como Oracle

Mysql

/*
Navicat MySQL Data Transfer

Source Server         : 10.19.34.3_ehr_admin
Source Server Version : 50639
Source Host           : 10.19.34.3:3306
Source Database       : attend_base_dev

Target Server Type    : MYSQL
Target Server Version : 50639
File Encoding         : 65001

Date: 2020-08-28 16:29:36
*/

-- SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `qrtz_CALENDARS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_CALENDARS`;
CREATE TABLE `qrtz_CALENDARS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `CALENDAR_NAME` varchar(200) NOT NULL,
  `CALENDAR` blob NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='日历信息';

-- ----------------------------
-- Records of qrtz_CALENDARS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_FIRED_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_FIRED_TRIGGERS`;
CREATE TABLE `qrtz_FIRED_TRIGGERS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `ENTRY_ID` varchar(95) NOT NULL COMMENT '组标识',
  `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  `INSTANCE_NAME` varchar(200) NOT NULL COMMENT '当前实例的名称',
  `FIRED_TIME` bigint(13) NOT NULL COMMENT '当前执行时间',
  `SCHED_TIME` bigint(13) NOT NULL COMMENT '计划时间',
  `PRIORITY` int(11) NOT NULL COMMENT '权重',
  `STATE` varchar(16) NOT NULL COMMENT '状态:WAITING:等待 \r\nPAUSED:暂停 \r\nACQUIRED:正常执行 \r\nBLOCKED:阻塞 \r\nERROR:错误',
  `JOB_NAME` varchar(200) DEFAULT NULL COMMENT '作业名称',
  `JOB_GROUP` varchar(200) DEFAULT NULL COMMENT '作业组',
  `IS_NONCONCURRENT` varchar(1) DEFAULT NULL COMMENT '是否并行',
  `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL COMMENT '是否要求唤醒',
  PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
  KEY `IDX_qrtz_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
  KEY `IDX_qrtz_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
  KEY `IDX_qrtz_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_qrtz_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_qrtz_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_qrtz_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='保存已经触发的触发器状态信息';

-- ----------------------------
-- Records of qrtz_FIRED_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_JOB_DETAILS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_JOB_DETAILS`;
CREATE TABLE `qrtz_JOB_DETAILS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `JOB_NAME` varchar(200) NOT NULL COMMENT '集群中job的名字',
  `JOB_GROUP` varchar(200) NOT NULL COMMENT '集群中job的所属组的名字',
  `DESCRIPTION` varchar(250) DEFAULT NULL COMMENT '描述',
  `JOB_CLASS_NAME` varchar(250) NOT NULL COMMENT '作业程序类名',
  `IS_DURABLE` varchar(1) NOT NULL COMMENT '是否持久',
  `IS_NONCONCURRENT` varchar(1) NOT NULL COMMENT '是否并行',
  `IS_UPDATE_DATA` varchar(1) NOT NULL COMMENT '是否更新',
  `REQUESTS_RECOVERY` varchar(1) NOT NULL COMMENT '是否要求唤醒',
  `JOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_qrtz_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
  KEY `IDX_qrtz_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job 详细信息';

-- ----------------------------
-- Records of qrtz_JOB_DETAILS
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_LOCKS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_LOCKS`;
CREATE TABLE `qrtz_LOCKS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `LOCK_NAME` varchar(40) NOT NULL COMMENT '锁名称',
  PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存储程序的悲观锁的信息(假如使用了悲观锁) ';

-- ----------------------------
-- Records of qrtz_LOCKS

-- ----------------------------
-- Table structure for `qrtz_PAUSED_TRIGGER_GRPS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_PAUSED_TRIGGER_GRPS`;
CREATE TABLE `qrtz_PAUSED_TRIGGER_GRPS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存放暂停掉的触发器';

-- ----------------------------
-- Records of qrtz_PAUSED_TRIGGER_GRPS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_SCHEDULER_STATE`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SCHEDULER_STATE`;
CREATE TABLE `qrtz_SCHEDULER_STATE` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `INSTANCE_NAME` varchar(200) NOT NULL COMMENT '实例名称',
  `LAST_CHECKIN_TIME` bigint(13) NOT NULL COMMENT '最后的检查时间',
  `CHECKIN_INTERVAL` bigint(13) NOT NULL COMMENT '检查间隔',
  PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='调度器状态';

-- ----------------------------
-- Records of qrtz_SCHEDULER_STATE

-- ----------------------------
-- Table structure for `qrtz_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_TRIGGERS`;
CREATE TABLE `qrtz_TRIGGERS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  `JOB_NAME` varchar(200) NOT NULL COMMENT '作业名称',
  `JOB_GROUP` varchar(200) NOT NULL COMMENT '作业组',
  `DESCRIPTION` varchar(250) DEFAULT NULL COMMENT '描述',
  `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL COMMENT '下次执行时间',
  `PREV_FIRE_TIME` bigint(13) DEFAULT NULL COMMENT '前一次',
  `PRIORITY` int(11) DEFAULT NULL COMMENT '优先权',
  `TRIGGER_STATE` varchar(16) NOT NULL COMMENT '触发器状态',
  `TRIGGER_TYPE` varchar(8) NOT NULL COMMENT '触发器类型',
  `START_TIME` bigint(13) NOT NULL COMMENT '开始时间',
  `END_TIME` bigint(13) DEFAULT NULL COMMENT '结束时间',
  `CALENDAR_NAME` varchar(200) DEFAULT NULL COMMENT '日历名称',
  `MISFIRE_INSTR` smallint(2) DEFAULT NULL COMMENT '失败次数',
  `JOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_qrtz_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_qrtz_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_qrtz_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
  KEY `IDX_qrtz_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_qrtz_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
  KEY `IDX_qrtz_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_qrtz_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_qrtz_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
  KEY `IDX_qrtz_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
  KEY `IDX_qrtz_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
  KEY `IDX_qrtz_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
  KEY `IDX_qrtz_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='触发器';

-- ----------------------------
-- Records of qrtz_TRIGGERS

-- ----------------------------
-- Table structure for `qrtz_SIMPLE_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SIMPLE_TRIGGERS`;
CREATE TABLE `qrtz_SIMPLE_TRIGGERS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  `REPEAT_COUNT` bigint(7) NOT NULL COMMENT '重复次数',
  `REPEAT_INTERVAL` bigint(12) NOT NULL COMMENT '重复间隔',
  `TIMES_TRIGGERED` bigint(10) NOT NULL COMMENT '触发次数',
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='简单的触发器';

-- ----------------------------
-- Records of qrtz_SIMPLE_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_SIMPROP_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SIMPROP_TRIGGERS`;
CREATE TABLE `qrtz_SIMPROP_TRIGGERS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  `STR_PROP_1` varchar(512) DEFAULT NULL,
  `STR_PROP_2` varchar(512) DEFAULT NULL,
  `STR_PROP_3` varchar(512) DEFAULT NULL,
  `INT_PROP_1` int(11) DEFAULT NULL,
  `INT_PROP_2` int(11) DEFAULT NULL,
  `LONG_PROP_1` bigint(20) DEFAULT NULL,
  `LONG_PROP_2` bigint(20) DEFAULT NULL,
  `DEC_PROP_1` decimal(13,4) DEFAULT NULL,
  `DEC_PROP_2` decimal(13,4) DEFAULT NULL,
  `BOOL_PROP_1` varchar(1) DEFAULT NULL,
  `BOOL_PROP_2` varchar(1) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器';

-- ----------------------------
-- Records of qrtz_SIMPROP_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_BLOB_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_BLOB_TRIGGERS`;
CREATE TABLE `qrtz_BLOB_TRIGGERS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名',
  `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  `BLOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='以Blob 类型存储的触发器';

-- ----------------------------
-- Records of qrtz_BLOB_TRIGGERS
-- ----------------------------

-- ----------------------------
-- Table structure for `qrtz_CRON_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_CRON_TRIGGERS`;
CREATE TABLE `qrtz_CRON_TRIGGERS` (
  `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
  `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
  `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
  `CRON_EXPRESSION` varchar(120) NOT NULL COMMENT '时间表达式',
  `TIME_ZONE_ID` varchar(80) DEFAULT NULL COMMENT '时区ID     nvarchar     80',
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='定时触发器';

-- ----------------------------
-- Records of qrtz_CRON_TRIGGERS
-- ----------------------------

Oráculo

create table QRTZ_CALENDARS
(
  sched_name    VARCHAR2(120) not null,
  calendar_name VARCHAR2(200) not null,
  calendar      BLOB not null
);
alter table QRTZ_CALENDARS
  add constraint PK_QRTZ_CALENDARS primary key (SCHED_NAME, CALENDAR_NAME);

create table QRTZ_FIRED_TRIGGERS
(
  sched_name        VARCHAR2(120) not null,
  entry_id          VARCHAR2(95) not null,
  trigger_name      VARCHAR2(200) not null,
  trigger_group     VARCHAR2(200) not null,
  instance_name     VARCHAR2(200) not null,
  fired_time        NUMBER(13) not null,
  sched_time        NUMBER(13) not null,
  priority          INTEGER not null,
  state             VARCHAR2(16) not null,
  job_name          VARCHAR2(200),
  job_group         VARCHAR2(200),
  is_nonconcurrent  VARCHAR2(1),
  requests_recovery VARCHAR2(1)
);
alter table QRTZ_FIRED_TRIGGERS
  add constraint PK_QRTZ_FIRED_TRIGGERS primary key (SCHED_NAME, ENTRY_ID);

create table QRTZ_JOB_DETAILS
(
  sched_name        VARCHAR2(120) not null,
  job_name          VARCHAR2(200) not null,
  job_group         VARCHAR2(200) not null,
  description       VARCHAR2(250),
  job_class_name    VARCHAR2(250) not null,
  is_durable        VARCHAR2(1) not null,
  is_nonconcurrent  VARCHAR2(1) not null,
  is_update_data    VARCHAR2(1) not null,
  requests_recovery VARCHAR2(1) not null,
  job_data          BLOB
);
alter table QRTZ_JOB_DETAILS
  add constraint PK_QRTZ_JOB_DETAILS primary key (SCHED_NAME, JOB_NAME, JOB_GROUP);

create table QRTZ_LOCKS
(
  sched_name VARCHAR2(120) not null,
  lock_name  VARCHAR2(40) not null
);
alter table QRTZ_LOCKS
  add constraint PK_QRTZ_LOCKS primary key (SCHED_NAME, LOCK_NAME);

create table QRTZ_PAUSED_TRIGGER_GRPS
(
  sched_name    VARCHAR2(120) not null,
  trigger_group VARCHAR2(200) not null
);
alter table QRTZ_PAUSED_TRIGGER_GRPS
  add constraint PK__TRIGGER_GRPS primary key (SCHED_NAME, TRIGGER_GROUP);

create table QRTZ_SCHEDULER_STATE
(
  sched_name        VARCHAR2(120) not null,
  instance_name     VARCHAR2(200) not null,
  last_checkin_time NUMBER(13) not null,
  checkin_interval  NUMBER(13) not null
);
alter table QRTZ_SCHEDULER_STATE
  add constraint PK_QRTZ_SCHEDULER_STATE primary key (SCHED_NAME, INSTANCE_NAME);

create table QRTZ_TRIGGERS
(
  sched_name     VARCHAR2(120) not null,
  trigger_name   VARCHAR2(200) not null,
  trigger_group  VARCHAR2(200) not null,
  job_name       VARCHAR2(200) not null,
  job_group      VARCHAR2(200) not null,
  description    VARCHAR2(250),
  next_fire_time NUMBER(13),
  prev_fire_time NUMBER(13),
  priority       INTEGER,
  trigger_state  VARCHAR2(16) not null,
  trigger_type   VARCHAR2(8) not null,
  start_time     NUMBER(13) not null,
  end_time       NUMBER(13),
  calendar_name  VARCHAR2(200),
  misfire_instr  NUMBER(2),
  job_data       BLOB
);

alter table QRTZ_TRIGGERS
  add constraint PK_QRTZ_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_SIMPLE_TRIGGERS
(
  sched_name      VARCHAR2(120) not null,
  trigger_name    VARCHAR2(200) not null,
  trigger_group   VARCHAR2(200) not null,
  repeat_count    NUMBER(7) not null,
  repeat_interval NUMBER(12) not null,
  times_triggered NUMBER(10) not null
);
alter table QRTZ_SIMPLE_TRIGGERS
  add constraint PK_QRTZ_SIMPLE_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_SIMPROP_TRIGGERS
(
  sched_name    VARCHAR2(120) not null,
  trigger_name  VARCHAR2(200) not null,
  trigger_group VARCHAR2(200) not null,
  str_prop_1    VARCHAR2(512),
  str_prop_2    VARCHAR2(512),
  str_prop_3    VARCHAR2(512),
  int_prop_1    INTEGER,
  int_prop_2    INTEGER,
  long_prop_1   NUMBER,
  long_prop_2   NUMBER,
  dec_prop_1    NUMBER(13,4),
  dec_prop_2    NUMBER(13,4),
  bool_prop_1   VARCHAR2(1),
  bool_prop_2   VARCHAR2(1)
);
alter table QRTZ_SIMPROP_TRIGGERS
  add constraint PK_QRTZ_SIMPROP_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_BLOB_TRIGGERS
(
  sched_name    VARCHAR2(120) not null,
  trigger_name  VARCHAR2(200) not null,
  trigger_group VARCHAR2(200) not null,
  blob_data     BLOB
);
alter table QRTZ_BLOB_TRIGGERS
  add constraint PK_QRTZ_BLOB_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

create table QRTZ_CRON_TRIGGERS
(
  sched_name      VARCHAR2(120) not null,
  trigger_name    VARCHAR2(200) not null,
  trigger_group   VARCHAR2(200) not null,
  cron_expression VARCHAR2(200) not null,
  time_zone_id    VARCHAR2(80)
);
alter table QRTZ_CRON_TRIGGERS
  add constraint PK_QRTZ_CRON_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);

delete from QRTZ_JOB_DETAILS;
delete from QRTZ_CRON_TRIGGERS;
delete from QRTZ_BLOB_TRIGGERS;
delete from QRTZ_CALENDARS;
delete from QRTZ_FIRED_TRIGGERS;
delete from QRTZ_LOCKS;
delete from QRTZ_PAUSED_TRIGGER_GRPS;
delete from QRTZ_SCHEDULER_STATE;
delete from QRTZ_SIMPLE_TRIGGERS;
delete from QRTZ_SIMPROP_TRIGGERS;
delete from QRTZ_TRIGGERS;

Maven

Yo uso Springboot2.1 en segundo plano aquí

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-quartz</artifactId>
      </dependency>

application.yml

quartz:
    #quartz相关属性配置
    properties:
      org:
        quartz:
          scheduler:
            instanceName: clusteredScheduler #调度器的实例名
            instanceId: AUTO #调度器编号自动生成
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: qrtz_ #数据库表名前缀
            isClustered: true #开启分布式部署
            clusterCheckinInterval: 10000 #分布式节点有效性检查时间间隔,单位:秒
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool #自带的线程池实现类
            threadCount: 10 #开启10个线程
            threadPriority: 5 #工作者线程的优先级
            threadsInheritContextClassLoaderOfInitializingThread: true
    #数据库方式
    job-store-type: jdbc

Frijol

import org.quartz.JobDataMap;
import java.util.Date;

/**
 * @program: QuartzBean 
 * @description:
 * @author: Yuwl
 * @create: 2020-06-02 18:36
 **/
public class QuartzBean {

    /** 任务id */
    private String  id;

    /** 任务名称 */
    private String jobName;

    /** 任务组 */
    private String jobGroup;

    /** 任务执行类 */
    private String jobClass;

    /** 任务状态 启动还是暂停*/
    private Integer status;

    /**
     * 任务开始时间
     */
    private Date startTime;

    /**
     * 任务循环间隔-单位:分钟
     */
    private Integer interval;

    /**
     * 任务结束时间
     */
    private Date endTime;

    /** 任务运行时间表达式 */
    private String cronExpression;

    private JobDataMap jobDataMap;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName;
    }

    public String getJobClass() {
        return jobClass;
    }

    public void setJobClass(String jobClass) {
        this.jobClass = jobClass;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }

    public Integer getInterval() {
        return interval;
    }

    public void setInterval(Integer interval) {
        this.interval = interval;
    }

    public Date getEndTime() {
        return endTime;
    }

    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }

    public JobDataMap getJobDataMap() {
        return jobDataMap;
    }

    public void setJobDataMap(JobDataMap jobDataMap) {
        this.jobDataMap = jobDataMap;
    }

    public String getJobGroup() {
        return jobGroup;
    }

    public void setJobGroup(String jobGroup) {
        this.jobGroup = jobGroup;
    }
}

Servicio

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.framework.quartz.QuartzBean;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @program: QuartzJobService 
 * @description:
 * @author: Yuwl
 * @create: 2020-07-21 17:00
 **/
@Service
public class QuartzJobService {

    @Autowired
    private Scheduler scheduler;

    /**
     * 创建定时任务Simple
     * quartzBean.getInterval()==null表示单次提醒,
     * 否则循环提醒(quartzBean.getEndTime()!=null)
     * @param quartzBean
     */
    public void createScheduleJobSimple(QuartzBean quartzBean) throws Exception{
        //获取到定时任务的执行类  必须是类的绝对路径名称
        //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
        Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
        // 构建定时任务信息
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
                .setJobData(quartzBean.getJobDataMap())
                .build();
        // 设置定时任务执行方式
        SimpleScheduleBuilder simpleScheduleBuilder = null;
        if (quartzBean.getInterval() ==  null) { //单次
            simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
        } else { //循环
            simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(quartzBean.getInterval());
        }
        // 构建触发器trigger
        Trigger trigger = null;
        if (quartzBean.getInterval() ==  null) { //单次
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(quartzBean.getJobName(),ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
                    .withSchedule(simpleScheduleBuilder)
                    .startAt(quartzBean.getStartTime())
                    .build();
        } else { //循环
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(quartzBean.getJobName(),ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
                    .withSchedule(simpleScheduleBuilder)
                    .startAt(quartzBean.getStartTime())
                    .endAt(quartzBean.getEndTime())
                    .build();
        }
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 创建定时任务Cron
     * 定时任务创建之后默认启动状态
     * @param quartzBean  定时任务信息类
     * @throws Exception
     */
    public void createScheduleJobCron(QuartzBean quartzBean) throws Exception{
        //获取到定时任务的执行类  必须是类的绝对路径名称
        //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
        Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
        // 构建定时任务信息
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).setJobData(quartzBean.getJobDataMap()).build();
        // 设置定时任务执行方式
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
        // 构建触发器trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 根据任务名称暂停定时任务
     * @param jobName 定时任务名称
     * @param jobGroup 任务组(没有分组传值null)
     * @throws Exception
     */
    public void pauseScheduleJob(String jobName,String jobGroup) throws Exception{
        JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        scheduler.pauseJob(jobKey);
    }

    /**
     * 根据任务名称恢复定时任务
     * @param jobName    定时任务名
     * @param jobGroup 任务组(没有分组传值null)
     * @throws SchedulerException
     */
    public void resumeScheduleJob(String jobName,String jobGroup) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        scheduler.resumeJob(jobKey);
    }

    /**
     * 根据任务名称立即运行一次定时任务
     * @param jobName       定时任务名称
     * @param jobGroup 任务组(没有分组传值null)
     * @throws SchedulerException
     */
    public void runOnce(String jobName,String jobGroup) throws Exception{
        JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        scheduler.triggerJob(jobKey);
    }

    /**
     * 更新定时任务Simple
     * @param quartzBean  定时任务信息类
     * @throws SchedulerException
     */
    public void updateScheduleJobSimple(QuartzBean quartzBean) throws Exception {
        //获取到对应任务的触发器
        TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null);
        // 设置定时任务执行方式
        SimpleScheduleBuilder simpleScheduleBuilder = null;
        if (quartzBean.getInterval() ==  null) { //单次
            simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
        } else { //循环
            simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(quartzBean.getInterval());
        }
        // 构建触发器trigger
        Trigger trigger = null;
        if (quartzBean.getInterval() ==  null) { //单次
            trigger = TriggerBuilder.newTrigger()
                    .withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
                    .withSchedule(simpleScheduleBuilder)
                    .startAt(quartzBean.getStartTime())
                    .build();
        } else { //循环
            TriggerBuilder.newTrigger()
                    .withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
                    .withSchedule(simpleScheduleBuilder)
                    .startAt(quartzBean.getStartTime())
                    .endAt(quartzBean.getEndTime())
                    .build();
        }
        //重置对应的job
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 更新定时任务Cron
     * @param quartzBean  定时任务信息类
     * @throws SchedulerException
     */
    public void updateScheduleJobCron(QuartzBean quartzBean) throws Exception {
        //获取到对应任务的触发器
        TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
        //设置定时任务执行方式
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
        //重新构建任务的触发器trigger
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        //重置对应的job
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    /**
     * 根据定时任务名称从调度器当中删除定时任务
     * @param jobName   定时任务名称
     * @param jobGroup 任务组(没有分组传值null)
     * @throws SchedulerException
     */
    public void deleteScheduleJob(String jobName,String jobGroup) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        scheduler.deleteJob(jobKey);
    }

    /**
     * 获取任务状态
     * @param jobName
     * @param jobGroup 任务组(没有分组传值null)
     * @return
     * (" BLOCKED ", " 阻塞 ");
     * ("COMPLETE", "完成");
     * ("ERROR", "出错");
     * ("NONE", "不存在");
     * ("NORMAL", "正常");
     * ("PAUSED", "暂停");
     */
    public String getScheduleJobStatus(String jobName,String jobGroup) throws Exception {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        Trigger.TriggerState state = scheduler.getTriggerState(triggerKey);
        return state.name();
    }

    /**
     * 根据定时任务名称来判断任务是否存在
     * @param jobName   定时任务名称
     * @param jobGroup 任务组(没有分组传值null)
     * @throws SchedulerException
     */
    public Boolean checkExistsScheduleJob(String jobName,String jobGroup) throws Exception {
        JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        return scheduler.checkExists(jobKey);
    }

    /**
     * 根据任务組刪除定時任务
     * @param jobGroup 任务组
     * @throws SchedulerException
     */
    public Boolean deleteGroupJob(String jobGroup) throws Exception {
        GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroup);
        Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
        List<JobKey> jobkeyList = new ArrayList<JobKey>();
        jobkeyList.addAll(jobkeySet);
        return scheduler.deleteJobs(jobkeyList);
    }

    /**
     * 根据任务組批量刪除定時任务
     * @param jobkeyList
     * @throws SchedulerException
     */
    public Boolean batchDeleteGroupJob(List<JobKey> jobkeyList) throws Exception {
        return scheduler.deleteJobs(jobkeyList);
    }

    /**
     * 根据任务組批量查询出jobkey
     * @param jobGroup 任务组
     * @throws SchedulerException
     */
    public void batchQueryGroupJob(List<JobKey> jobkeyList,String jobGroup) throws Exception {
        GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroup);
        Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
        jobkeyList.addAll(jobkeySet);
    }
}

Trabajo

package com.quartz.demo.job

import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @program: job
 * @description:
 * @author: Yuwl
 * @create: 2020-06-02 18:07
 **/
@Component
public class MyTask extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        JobKey jobKey = context.getJobDetail().getKey();
        JobDataMap map = context.getJobDetail().getJobDataMap();
        String userId = map.getString("userId");
        System.out.println("SimpleJob says: " + jobKey + ", userId: " + userId + " executing at " + new Date());
    }
}

Controlador

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.quartz.QuartzBean;
import com.ruoyi.framework.quartz.service.QuartzJobService;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
import java.util.Date;

/**
 * @program: JobController 
 * @description:
 * @author: Yuwl
 * @create: 2020-07-21 17:08
 **/
@RestController
@RequestMapping("/api/quartz/")
public class JobController {

    @Autowired
    private QuartzJobService quartzJobService;

    //创建&启动
    @GetMapping("startSimpleJob")
    public String startSimpleJob() throws SchedulerException, ClassNotFoundException, ParseException {
        QuartzBean quartzBean = new QuartzBean();
        quartzBean.setJobClass("com.quartz.demo.job.MyTask");
        quartzBean.setJobName("job1");
        JobDataMap map = new JobDataMap();
        map.put("userId", "123456");
        quartzBean.setJobDataMap(map);
        Date now = new Date();
        quartzBean.setStartTime(DateUtils.addSeconds(now, 10));
        quartzBean.setInterval(10);
        quartzBean.setEndTime(DateUtils.addMinutes(now, 1));
        try {
            quartzJobService.createScheduleJobSimple(quartzBean);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "startJob Success!";
    }

    /**
     * 创建cron Job
     * @param quartzBean
     * @return
     */
    @RequestMapping("/createCronJob")
    @ResponseBody
    public String  createJob(QuartzBean quartzBean)  {
        try {
            //进行测试所以写死
            quartzBean.setJobClass("com.quartz.demo.job.MyTask");
            quartzBean.setJobName("job1");
            quartzBean.setCronExpression("*/5 * * * * ?");
            quartzJobService.createScheduleJobCron(quartzBean);
        } catch (Exception e) {
            return "创建失败";
        }
        return "创建成功";
    }

    /**
     * 暂停job
     * @return
     */
    @RequestMapping(value = {"/pauseJob/{jobName}","/pauseJob/{jobName}/{jobGroup}"})
    @ResponseBody
    public String  pauseJob(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
        try {
        quartzJobService.pauseScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        } catch (Exception e) {
            return "暂停失败";
        }
        return "暂停成功";
    }

    @RequestMapping(value = {"/resume/{jobName}","/resume/{jobName}/{jobGroup}"})
    @ResponseBody
    public String  resume(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
        try {
    quartzJobService.resumeScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        } catch (Exception e) {
            return "启动失败";
        }
        return "启动成功";
    }

    @RequestMapping(value = {"/delete/{jobName}","/delete/{jobName}/{jobGroup}"})
    public String  delete(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
        try {
            quartzJobService.deleteScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        } catch (Exception e) {
            return "删除失败";
        }
        return "删除成功";
    }

    @RequestMapping(value = {"/check/{jobName}","/check/{jobName}/{jobGroup}"})
    public String  check(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
        try {
            if(quartzJobService.checkExistsScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null)){
                return "存在定时任务:"+jobName;
            }else{
                return "不存在定时任务:"+jobName;
            }
        } catch (Exception e) {
            return "查询任务失败";
        }
    }

    @RequestMapping(value = {"/status/{jobName}","/status/{jobName}/{jobGroup}"})
    @ResponseBody
    public String  status(@PathVariable("jobName") String  jobName,@PathVariable(required = false) String jobGroup)  {
        try {
            return quartzJobService.getScheduleJobStatus(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
        } catch (Exception e) {
            return "获取状态失败";
        }
        //return "获取状态成功";
    }

}

prueba

http: // localhost: 8080 / api / quartz / startSimpleJob

Autor: Kobayashi, un ingeniero de desarrollo senior de small fox E, se centra en la coordinación de la plataforma móvil office light El desarrollo de software y aplicaciones SAAS desarrolló
recientemente un software de oficina móvil Fox Little E

Supongo que te gusta

Origin blog.51cto.com/14942009/2536639
Recomendado
Clasificación