Quartz分布式定时任务
前言:
项目需要执行定时任务,该类定时任务只需要实现类似Spring原生的@Scheudle注解的定时方法即可,无需考虑分片、刷新及重启,且因项目是多实例,所以需要考虑实现分布式,考察了目前开源的几款分布式定时任务产品
xxl-job 需要部署server端,考虑项目不需要依赖这么重的第三方的server,所以被pass
elastic-job-lite 这个需要的zk版本要3.6以上 公司已有的zk环境是3.4.5 所以不想再单独部署zk,所以也被pass
quartz 分布式定时任务是依靠数据库悲观锁的机制实现的,只需要依赖数据库,项目本身是有数据库存储依赖的,对项目的侵入性较小
以下为改造过程
引入maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
增加配置application.properties
# 定时任务配置
spring.quartz.job-store-type=jdbc
spring.quartz.wait-for-jobs-to-complete-on-shutdown=true
spring.quartz.overwrite-existing-jobs=true
spring.quartz.startup-delay=10S
spring.quartz.properties.org.quartz.scheduler.instanceName=exampleInstanceName
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.jobStore.useProperties=false
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=5000
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount=10
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
执行sql
项目中存在数据库的连接配置,存在spring-boot-starter-jdbc依赖
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
#
# By: Ron Cordell - roncordell
# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM. DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS; CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(190) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB; CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB; CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB; CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB; CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB; CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP); CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); commit;以下是代码列表清单
实现逻辑:
1> ScheduleJobInit 初始化时加载所有AbstractJob 的子类
2> 获取子类的 beanName ,及ScheduleTag注解注解的方法名称methodName,及注解的cron()方法
3> 根据beanName+methodName 生产jobId
4> 如果外部有 beanName+methodName+cron 配置取外部配置,没值取注解的cron()值
5> 具体需要定时执行的类和方法 需满足 在spring容器里、实现AbstractJob 接口、方法上加上ScheduleTag(cron="") 注解信息即可
ScheduleJobEntity job信息类
@Data
public class ScheduleJobEntity { public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
private String jobId;
private String beanName;
private String methodName;
private String params;
private String cronExpression; public String getJobId() {
return StrUtil.join("_", beanName, methodName);
}
}
ScheduleUtils schedule工具类
/**
* 定时任务工具类
*/
public class ScheduleUtils {
private final static String JOB_NAME = "job_";
private final static String JOB_PARAMS_NAME = "params";
private final static String JOB_CRON_NAME = "cron"; /**
* 获取触发器key
*/
public static TriggerKey getTriggerKey(String jobId) {
return TriggerKey.triggerKey(JOB_NAME + jobId);
} /**
* 获取jobKey
*/
public static JobKey getJobKey(String jobId) {
return JobKey.jobKey(JOB_NAME + jobId);
} public static void initJob(Scheduler scheduler, Class jobClass, Map<String, String> properties) {
ScheduleJobEntity scheduleJob = new ScheduleJobEntity();
scheduleJob.setBeanName(StringUtils.uncapitalize(jobClass.getSimpleName()));
Method[] methods = MethodUtils.getMethodsWithAnnotation(jobClass, ScheduleTag.class);
for (Method method : methods) {
ScheduleTag scheduleTag = method.getAnnotation(ScheduleTag.class);
String params = "";
String cron = "";
if (scheduleTag != null) {
params = scheduleTag.params();
cron = scheduleTag.corn();
}
if (CollectionUtil.isNotEmpty(properties)) {
String paramsDynamic = properties.get(joinKey(scheduleJob.getBeanName(), method.getName(), JOB_PARAMS_NAME));
String cronDynamic = properties.get(joinKey(scheduleJob.getBeanName(), method.getName(), JOB_CRON_NAME));
if (StringUtils.isNotEmpty(paramsDynamic)) {
params = paramsDynamic;
}
if (StringUtils.isNotEmpty(cronDynamic)) {
cron = cronDynamic;
}
}
scheduleJob.setMethodName(method.getName());
scheduleJob.setParams(params);
scheduleJob.setCronExpression(cron);
CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId());
if (cronTrigger == null) {
createScheduleJob(scheduler, scheduleJob);
} else {
updateScheduleJob(scheduler, scheduleJob);
}
}
} private static String joinKey(String beanName, String methodName, String key) {
return StrUtil.join("_", beanName, methodName, key);
} /**
* 获取表达式触发器
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
try {
return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
} catch (SchedulerException e) {
throw new QeteshException(e, "获取定时任务CronTrigger出现异常");
}
} /**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getJobId())).build(); // 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
.withMisfireHandlingInstructionDoNothing(); // 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build(); // 放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, JSONUtil.toJsonStr(scheduleJob)); scheduler.scheduleJob(jobDetail, trigger); } catch (SchedulerException e) {
throw new QeteshException(e, "创建定时任务失败");
}
} /**
* 更新定时任务
*/
public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
try {
TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId()); // 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
.withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId()); // 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); // 参数
trigger.getJobDataMap().put(ScheduleJobEntity.JOB_PARAM_KEY, JSONUtil.toJsonStr(scheduleJob)); scheduler.rescheduleJob(triggerKey, trigger); } catch (SchedulerException e) {
throw new QeteshException(e, "更新定时任务失败");
}
}
}
ScheduleRunnable 具体任务执行反射线程类
/**
* 执行定时任务
*/
public class ScheduleRunnable implements Runnable {
private final Object target;
private final Method method;
private final String params; public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException {
this.target = SpringContextHolder.getBean(beanName);
this.params = params;
if (StringUtils.isNotBlank(params)) {
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
this.method = target.getClass().getDeclaredMethod(methodName);
}
} @Override
public void run() {
try {
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(params)) {
method.invoke(target, params);
} else {
method.invoke(target);
}
} catch (Exception e) {
throw new QeteshException(e, "执行定时任务失败");
}
}
}
ScheduleJob job类
/**
* 定时任务
*/
@Slf4j
public class ScheduleJob extends QuartzJobBean { private static final ExecutorService service = Executors.newSingleThreadExecutor(); @Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
String jsonJob = context.getMergedJobDataMap().getString(ScheduleJobEntity.JOB_PARAM_KEY);
ScheduleJobEntity scheduleJob = JSONUtil.toBean(jsonJob, ScheduleJobEntity.class);
// 任务开始时间
long startTime = System.currentTimeMillis();
try {
// 执行任务
log.info("任务准备执行,任务ID:" + scheduleJob.getJobId());
ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(),
scheduleJob.getMethodName(), scheduleJob.getParams());
Future<?> future = service.submit(task);
future.get();
// 任务执行总时长
long times = System.currentTimeMillis() - startTime;
log.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + " 总共耗时:" + times + "毫秒");
} catch (Exception e) {
log.error("任务执行失败,任务ID:" + scheduleJob.getJobId(), e);
// 任务执行总时长
long times = System.currentTimeMillis() - startTime;
log.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + " 总共耗时:" + times + "毫秒");
} }
}
ScheduleTag 注解类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Inherited
public @interface ScheduleTag { String corn() default "";
String params() default "";
}
AbstractJob job接口类,如果需要定时执行的方法需要继承该接口
public interface AbstractJob { }
ScheduleJobInit 初始化器
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ScheduleJobInit implements ApplicationContextAware, InitializingBean { private final Scheduler scheduler;
private final JobConfig jobConfig;
private ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
} @Override
public void afterPropertiesSet() throws Exception {
Collection<AbstractJob> jobList = applicationContext.getBeansOfType(AbstractJob.class).values();
if (CollectionUtil.isNotEmpty(jobList)) {
jobList.forEach(job -> ScheduleUtils.initJob(scheduler, job.getClass(), jobConfig.getProperties()));
} }
}
SimpleJob 简单示例job ,必须在spring容器内
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SimpleJob implements AbstractJob { // 每5秒执行一次
@ScheduleTag(corn = "*/5 * * * * ?")
public void test() {
log.info("test start...");
}
}
这里如果需要在配置文件里配置cron,需要增加如下配置
properties aicc.job.properties.simpleJob_test_cron=0 0/1 * * * ?
规则如下:
aicc.job.properties.
beanName(类名首字母小写).methodName(方法名).cron
Quartz分布式定时任务的更多相关文章
- Spring整合Quartz分布式定时任务
概述虽然单个Quartz实例能给予你很好的Job调度能力,但它不能满足典型的企业需求,如可伸缩性.高可靠性满足.假如你需要故障转移的能力并能运行日益增多的 Job,Quartz集群势必成为你应用的一部 ...
- 基于spring+quartz的分布式定时任务框架
问题背景 我公司是一个快速发展的创业公司,目前有200人,主要业务是旅游和酒店相关的,应用迭代更新周期比较快,因此,开发人员花费了更多的时间去更=跟上迭代的步伐,而缺乏了对整个系统的把控 没有集群之前 ...
- 3分钟掌握Quartz.net分布式定时任务的姿势
引言 长话短说,今天聊一聊分布式定时任务,我的流水账笔记: ASP.NET Core+Quartz.Net实现web定时任务 AspNetCore结合Redis实践消息队列 细心朋友稍一分析,就知道还 ...
- spring quartz分布式任务计划
spring quartz分布式任务计划 环境: 通过maven管理的spring mvc工程,且已经成功连接数据库. 数据库表结构 /*Table structure for table `qrtz ...
- Elastic-Job - 分布式定时任务框架
Elastic-Job - 分布式定时任务框架 摘要 Elastic-Job是ddframe中dd-job的作业模块中分离出来的分布式弹性作业框架.去掉了和dd-job中的监控和ddframe接入规范 ...
- Spring整合Quartz分布式调度
前言 为了保证应用的高可用和高并发性,一般都会部署多个节点:对于定时任务,如果每个节点都执行自己的定时任务,一方面耗费了系统资源,另一方面有些任务多次执行,可能引发应用逻辑问题,所以需要一个分布式的调 ...
- Spring整合Quartz分布式调度(山东数漫江湖)
前言 为了保证应用的高可用和高并发性,一般都会部署多个节点:对于定时任务,如果每个节点都执行自己的定时任务,一方面耗费了系统资源,另一方面有些任务多次执行,可能引发应用逻辑问题,所以需要一个分布式的调 ...
- Spring Boot Quartz 分布式集群任务调度实现
Spring Boot Quartz 主要内容 Spring Scheduler 框架 Quartz 框架,功能强大,配置灵活 Quartz 集群 mysql 持久化定时任务脚本(tables_mys ...
- Java分布式定时任务
分布式定时任务 elastic-job 可以实现任务分片 quartz 可以把任务存入数据库,实时生成任务(添加数据库添加定时任务) 文档 中文翻译 翻译2
- springboot整合xxl-job分布式定时任务【图文完整版】
一.前言 定时任务有很多种,有一些大的框架也有一些简单的实现. 比如常见的: JDK的Timer和TimerTask Quartz异步任务调度框架 分布式定时任务XXL-JOB Spring Task ...
随机推荐
- NLog 在NetCore中实现多实例注入DI, 实现多租户模式
通常, 我们在使用了 Microsoft.Extensions.DependencyInjection DI框架的情况下, 我们一般通过 .ConfigureLogging((HostBuilderC ...
- appium-解决uiautomatorviewer不能定位android7以上版本元素的方法
上图是android10模拟器,发现我们是无法连接模拟器识别的 解决方法: 在模拟器内打开指定页面然后截图,最后保存为uix文件,然后用adb拉到本地,一共四个命令,可以保存为.bat文件快捷执行(这 ...
- direasch目录扫描
direasch目录扫描工具 安装: 1.github源码下载解压 使用 git 安装:(推荐git clone https://github.com/maurosoria/dirsearch.git ...
- [rCore学习笔记 030] 虚拟地址与地址空间
时隔很久,终于忙里偷闲可以搞一搞rCore,上帝啊,保佑我日更吧,我真的很想学会. 导读部分 首先还是要看官方文档. 我决定看一遍然后自己表述一遍(智将). 这里反复提到MMU,就是因为之前学MCU的 ...
- img标签src引用网络图片,响应403的解决方法
在html页面加入<meta name="referrer" content="no-referrer">标签,就可以解决页面加载网络图片的问题, ...
- 解密prompt系列42. LLM通往动态复杂思维链之路
最近大家都在探讨和尝试复现OpenAI O1的思考效果,解码出的关键技术方向,包括之前已经探讨过的Inference Time Scaling在推理过程中进行路径决策和选择.但想要更优的Inferen ...
- 使用原生Web开发技术为在线客服系统提供网页版配置工具
升讯威在线客服与营销系统是基于 .net core / WPF 开发的一款在线客服软件,宗旨是: 开放.开源.共享.努力打造 .net 社区的一款优秀开源产品. 背景 随着下载私有化部署的用户越来越多 ...
- Vulhub Apache Httpd漏洞复现
目录 前言 多后缀解析漏洞 换行解析漏洞(CVE-2017-15715) 2.4.49 路径穿越漏洞(CVE-2021-41773) 2.4.50 路径穿越漏洞(CVE-2021-42013) SSR ...
- dotnet学习笔记-专题03-RabbitMQ-01
专题03--RabbitMQ 1. RabbitMQ安装 服务端 使用如下sh脚本安装: #!/bin/sh sudo apt-get install curl gnupg apt-transport ...
- Java单例对象同步问题探讨
在本文中,作者向大家讲述了Single Call 模式的原理,同时也介绍了Single Call 模式的实现问题. 评论: 邓明 (dengming@cn.ibm.com), 高级信息系统工程师, ...