如何用 ShedLock 让 Spring Boot 的定时任务在多实例环境下只执行一次
之前在Spring Boot教程中我们介绍了如何用 @Scheduled 注解来创建定时任务,Spring 的任务调度用起来确实顺手。可这种实现方式一上多实例(比如多副本部署),同一个定时任务会在每个节点都跑一遍,等于任务会重复执行。
原因很简单:默认情况下,Spring 不会在多个实例之间做调度同步。
这篇文章就聊聊怎么用 ShedLock,让定时任务在多实例环境下“同一时刻只跑一次”。顺便一提,它也能作为 Quartz 的替代。
Maven 依赖
先引入 shedlock-spring 这个依赖:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>6.3.1</version>
</dependency>
最新版本可以去 Maven Central 看。
配置
ShedLock 依赖“共享数据库”,并且要声明一个合适的 LockProvider。它会在库里新建一张表/文档,记录当前的锁。
目前它支持 Mongo、Couchbase、Elasticsearch、Redis、Hazelcast、ZooKeeper、Cassandra,以及任何带 JDBC 驱动的数据库。
示例我们用内存型 H2 数据库,方便演示。
要跑起来,先把 H2 和 JDBC 版的 ShedLock 依赖加上:
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>6.3.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.1.214</version>
</dependency>
然后建一张表,专门存锁:
CREATE TABLE shedlock (
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)
在 Spring Boot 里把数据源写到配置里,这样 DataSource 才能被注入。这里用 application.yml:
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:shedlock_DB;INIT=CREATE SCHEMA IF NOT EXISTS shedlock;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
接着用这个数据源配置下 LockProvider,写法很直观:
@Configuration
public class SchedulerConfiguration {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}
别忘了再加上两个注解:@EnableScheduling 和 @EnableSchedulerLock:
@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SpringBootShedlockApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootShedlockApplication.class, args);
}
}
defaultLockAtMostFor 表示执行节点挂了时,锁最多保留多久。格式用的是 ISO8601 持续时间。
下面的示例会演示怎么在方法上覆盖它。
创建任务
让 ShedLock 接管一个定时任务很简单:方法上同时加 @Scheduled 和 @SchedulerLock:
@Component
class BaeldungTaskScheduler {
@Scheduled(cron = "0 0/15 * * * ?")
@SchedulerLock(name = "TaskScheduler_scheduledTask",
lockAtLeastFor = "PT5M", lockAtMostFor = "PT14M")
public void scheduledTask() {
// ...
}
}
先说 @Scheduled:它支持 cron 表达式,上面的表达式表示“每 15 分钟执行一次”。
再说 @SchedulerLock:name 要唯一,一般用 类名_方法名 就够了。我们不希望同一个方法被同时运行,ShedLock 就是靠这个唯一名称来实现的。
我们还加了两个可选参数:
- lockAtLeastFor 用来保证最少持锁时间,让两次执行之间留出一定间隔。使用 “PT5M” 表示至少 5 分钟。换句话说,这个方法被 ShedLock 控制后,运行频率不会高于每 5 分钟一次。
- lockAtMostFor 用来指定在执行节点异常(比如宕机)时,锁最多会被保留多久。使用 “PT14M” 表示最多 14 分钟。
正常情况下任务结束会立即释放锁。其实在 @EnableSchedulerLock 里已经有默认值,这里只是展示如何在方法级别做覆盖。
总结
一句话总结:用 ShedLock,可以让 Spring 在多实例部署下也能把定时任务“稳稳只跑一次”。
如何用 ShedLock 让 Spring Boot 的定时任务在多实例环境下只执行一次的更多相关文章
- 【Spring Boot项目】Win7+JDK8+Tomcat8环境下的War包部署
一.pom.xml及启动类修改 pom.xml Step1:指定打包类型 <!-- 打包类型 jar 或 war --> <packaging>war</packagin ...
- Spring Boot配置定时任务
在项目开发过程中,经常需要定时任务来做一些内容,比如定时进行数据统计(阅读量统计),数据更新(生成每天的歌单推荐)等. Spring Boot默认已经实现了,我们只需要添加相应的注解就可以完成定时任务 ...
- Spring Boot:定时任务
在我们开发项目过程中,经常需要定时任务来帮助我们来做一些内容, Spring Boot 默认已经帮我们实行了,只需要添加相应的注解就可以实现 1.pom 包配置 pom 包里面只需要引入 Spring ...
- 【Spring Boot】定时任务
[Spring Boot]定时任务 测试用业务Service package com.example.schedule.service; import org.springframework.ster ...
- spring boot 创建定时任务
@Scheduled默认创建的线程是单线程,任务的执行会受到上一个任务的影响,创建定时任务也比较简单 123456789101112 @Component@Configuration //1.主要用于 ...
- Spring boot项目maven的profile多环境配置不自动替换变量的问题解决
Spring boot项目maven的profile多环境配置不自动替换变量的问题解决 在网上找了好久,配置都很简单,可是我的程序就是不能自动替换变量,最终单独测试,发现原来是引用spring b ...
- spring boot项目使用mybatis-plus代码生成实例
前言 mybatis-plus官方地址 https://baomidou.com mybatis-plus是mybatis的增强,不对mybatis做任何改变,涵盖了代码生成,自定义ID生成器,快速实 ...
- Spring boot创建定时任务
基于spring boot的应用创建定时任务不要太简单,给一个类加上@Configuration @EnableScheduling注解,然后给该类需要定时执行的方法加上@Scheduled(cron ...
- Spring Boot (29) 定时任务
使用场景:数据定时增量同步,定时发送邮件,爬虫定时抓取 定时任务概述 定时任务:顾名思义就是在特定/指 定的时间进行工作,比如我们的手机闹钟,他就是一种定时的任务. 实现方式: 1.Timer:JDK ...
- SpringBoot系列:Spring Boot集成定时任务Quartz
一.关于Quartz Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.在java企业级应用中,Q ...
随机推荐
- node运行ts
前言 node v23开始直接支持ts,也就是说可以直接 node xxx.ts. 但是v23成为lts还需要几个月时间吧. 那么再次之前我们应该怎么让他支持呢? tsc 标准的做法,将ts打包成js ...
- Create React App 被 React 官方抛弃
新的开始 2023年3月17号 react官方文档正式更新,还顺带搬了个家,连网址都变了. 被嫌弃的CRA 不知道小伙伴有没有留意到了没:曾经官方推荐 创建项目的脚手架工具 create-react- ...
- define##的作用
转载 博客园 C++/C 宏定义(define)中# ## 的含义
- libsvm matlab 上的安装
简介windows上matlab安装还是有一些坑的 首先 matlab2016a 安装一个 编译器 tdm64-gcc-4.9.2.exe 然后更改 libsvm 中的matlab make.m 重点 ...
- 企业IT部门在集成类项目中扮演的角色
随着企业信息化建设的不断深入,集成类项目成为企业发展的重要支撑.这类项目涉及场景多.系统杂.实施牵扯广.周期长,对技术和管理的要求极高.企业IT部门(信息化部门)作为企业的技术核心和纽带,对业务需求. ...
- English: 管道系统: plumbing、pipe、tube、duct、hose、conduit、line的区别
B737系列 [1-19通用] 同是管道:pipe.tube.duct.hose.conduit.line的区别 楼主 ryn_82 英语表示管子的词有点多. 光我们飞机手册就有pipe.tube.d ...
- SciTech-BigDataAIML-Boltzmann constant波尔兹曼常数 + Boltzmann Machine波尔兹曼机模型
SciTech-BigDataAIML- Boltzmann constant
- 洛谷P2357
这仅仅是过去写的一个记录,更详细请见树状数组详解,本题是作为例题讲解的. 洛谷同步链接 题目传送门 与普通树状数组不同的是,这次既需要单点修改.区间查询,又需要区间修改.单点查询. 对于数组 $a$ ...
- 视觉小说 文字游戏引擎 ink 可配合Unity
ink 是 inkle 发明的标记式语言,专门用在编写互动叙事游戏中,是制作文字游戏和游戏叙事的利器.使用了 ink 语言来叙事的游戏有比较知名的<80 天(80 Days)>等. 使用i ...
- huffman基础代码实现
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; const int INF=0x3f3f3f3f; ...