• 作者:老汪软件技巧
  • 发表时间:2024-11-20 07:02
  • 浏览量:

1.什么是ShedLock?

ShedLock 是一个 Java 库,通常用于分布式系统中,确保定时任务(Scheduled Tasks)在集群环境下只被某一个实例执行一次。它通过在共享资源(例如数据库或分布式缓存)中添加锁的方式,避免多个实例同时执行相同的任务

ShedLock 的工作原理分布式锁:锁的生命周期:支持的存储:应用场景1. 分布式定时任务控制2. 避免重复任务执行3. 事件驱动任务的幂等性4. 任务重试机制2.代码工程实验目的

使用ShedLock 来确保在分布式环境中只有一个实例能运行任务

pom.xml

"1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>3.2.1version>
    parent>
    <modelVersion>4.0.0modelVersion>
    <artifactId>shedlockartifactId>
    <properties>
        <maven.compiler.source>17maven.compiler.source>
        <maven.compiler.target>17maven.compiler.target>
    properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-autoconfigureartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlockgroupId>
            <artifactId>shedlock-springartifactId>
            <version>5.5.0version>
        dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlockgroupId>
            <artifactId>shedlock-provider-jdbc-templateartifactId>
            <version>5.5.0version>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-jpaartifactId>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.33version>
        dependency>
    dependencies>
project>

config

package com.demo.config;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

_定时任务集群_分布式定时器框架

import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; @Configuration public class ShedLockConfig { @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withJdbcTemplate(new JdbcTemplate(dataSource)) .usingDbTime() // Works with PostgreSQL, MySQL, MariaDb, MS SQL, Oracle, HSQL, H2, DB2, and others .build() ); } }

cron

package com.demo.cron;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SchedulerConfig {
    @Scheduled(cron = "0 0/1 * * * ?")
    @SchedulerLock(name = "scheduledTaskName", lockAtMostFor = "PT10M", lockAtLeastFor = "PT1M")
    public void scheduledTask() {
        //  some logic code
        System.out.println("Executing scheduled task");
    }
}

@SchedulerLocklockAtMostFor = "PT10M":lockAtLeastFor = "PT1M":任务逻辑配置文件

node1节点

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
server.port=8081

node2节点

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
server.port=8082

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库3.测试

启动node1节点

java -jar myapp.jar --spring.profiles.active=node1

启动node2节点

java -jar myapp.jar --spring.profiles.active=node2

通过控制台观察日志,可以发现,2个实例交替获取到锁执行,而不是同一时刻一起执行

4.注意事项任务时间控制: 确保任务的实际执行时间小于 lockAtMostFor,否则任务可能被其他实例重复执行。幂等性: 任务逻辑应尽量设计为幂等的(重复执行不会产生副作用),以应对锁机制的潜在异常情况。存储配置: 确保使用高可用的锁存储(如数据库或 Redis),否则锁机制可能失效。5.引用