SpringBoot2.x Integrates detailed usage of lightweight distributed timer task ShedLock3.x

 

Catalog

Preface

SpringBoot2.x Integrates detailed usage of lightweight distributed timer task ShedLock3.x

1. About ShedLock

2. Three Core Components of ShedLock

3. ShedLock uses three steps

4. SpringBoot Integrated ShedLock (JDBC-based to provide locks)

5. Two modes of Spring integrated ShedLock

Preface

Previously, according to project requirements, high availability of microservices was required, that is, multiple instances of a service were deployed, but there were many timed task scheduling issues involved (.).Think about it and use ShedLock temporarily to implement distributed timer task locks. This article focuses on the use of SpringBoot2.x integrated lightweight distributed timer task ShedLock3.x.

 

SpringBoot2.x Integrates detailed usage of lightweight distributed timer task ShedLock3.x

1. About ShedLock

ShedLock uses the idea of non-intrusive programming and annotates the functionality.ShedLock is a framework of timed tasks used in distributed environments to solve the problem of multiple instances of the same timed tasks executing repeatedly at the same time point. The solution is to record and lock a table in a common database so that only the first timed task executing at the same time point is successfully written to the database table.The corresponding recorded node can execute successfully while the other nodes skip the task directly.Of course, not only databases, but also JDBC, Redis, MongoDB, CosmosDB, DynamoDB, Zookeeper, Elastic Search, and so on, are the supported data storage types that have been implemented so far.

 

2. Three Core Components of ShedLock

Core - Lock Mechanism
Integration - Integration with applications through Spring AOP, Micronaut AOP, or handwritten code
Lock provider - Use relational databases (RDBMS), non-relational databases: external processes such as Mongo, Redis to provide locks

 

3. ShedLock uses three steps

1), Enable and configure Scheduled locks
2) Add a comment on the Scheduled task
3), Provider of configuration locks (JDBC, Redis, Mongo, etc.)

 

4. SpringBoot Integrated ShedLock (JDBC-based to provide locks)

1) New introduction of Spring integrated ShedLock dependency package in pom.xml

<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-spring</artifactId>
	<version>3.0.1</version>
</dependency>
<dependency>
	<groupId>net.javacrumbs.shedlock</groupId>
	<artifactId>shedlock-provider-jdbc-template</artifactId>
	<version>3.0.1</version>
</dependency>

 

2) Configure LockProvider, the JDBC used here, so you need to configure the JDBC LockProvider to create a new lock table-shedlock table in the database corresponding to each instance (note that the name must be the primary key) with the following statement:

CREATE TABLE shedlock(
    name VARCHAR(64), 
    lock_until TIMESTAMP(3) NULL, 
    locked_at TIMESTAMP(3) NULL, 
    locked_by VARCHAR(255), 
    PRIMARY KEY (name)
);
COMMENT ON COLUMN "shedlock"."name" IS 'Lock name ( name Must be primary key)';
COMMENT ON COLUMN "shedlock"."lock_until" IS 'Release lock time';
COMMENT ON COLUMN "shedlock"."locked_at" IS 'Acquire lock time';
COMMENT ON COLUMN "shedlock"."locked_by" IS 'Lock Provider';

*Note: External storage in the form of relational databases (RDBMS) must create table structures, not relational, such as non-relational databases such as Redis, where template s automatically create corresponding key-value pairs based on the lock name declared by the annotation @SchedulerLock to provide lock implementation.

 

3) Configure LockProvider. There are several configuration implementations for LockProvider, which are implemented by JDBC here.

package com.huazai.aiyou.common.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 javax.sql.DataSource;

/**
 * 
 * @author HuaZai
 * @contact who.seek.me@java98k.vip
 *          <ul>
 * @description Configure LockProvider
 *              </ul>
 * @className ShedlockConfig
 * @package com.huazai.aiyou.common.config
 * @createdTime 2019 March 20, 2003
 *
 * @version V1.0.0
 */
@Configuration
public class ShedlockConfig
{

	@Bean
	public LockProvider lockProvider(DataSource dataSource)
	{
		return new JdbcTemplateLockProvider(dataSource);
	}
}

There are, of course, finer-grained configurations that you can try on your own using Configuration objects, as follows:

new JdbcTemplateLockProvider(builder()
    .withTableName("shdlck")
    .withColumnNames(new ColumnNames("n", "lck_untl", "lckd_at", "lckd_by"))
    .withJdbcTemplate(new JdbcTemplate(getDatasource()))
    .withLockedByValue("my-value")
    .build())

*Note: Do not manually delete lock rows or documents from database tables when using ShedLock.ShedLock has an existing lock's memory cache, so the row will not be automatically recreated until the application restarts.You can edit rows or documents if you want, at the risk of holding only multiple locks.At 1.0.0 you can clear the cache by calling clearCache() on the LockProvider.

 

4) Add a new'@EnableSchedulerLock'comment to the project's startup class to open ShedLock

package com.huazai.aiyou.controller;

import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * 
 * @author HuaZai
 * @contact who.seek.me@java98k.vip
 *          <ul>
 * @description Portal Web Start Class
 *              </ul>
 * @className AiyouApplication
 * @package com.huazai.aiyou
 * @createdTime 2019 March 20, 2003
 *
 * @version V1.0.0
 */
@EnableHystrix
@EnableCaching
@EnableDiscoveryClient
@EnableFeignClients
@EnableEurekaClient
@EnableCircuitBreaker
@EnableAutoConfiguration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT20M", defaultLockAtLeastFor = "PT20M")
public class AiyouApplication
{

	public static void main(String[] args)
	{
		SpringApplication.run(AiyouApplication.class, args);
	}
}

 

5) Add the comment'@SchedulerLock'to the Scheduled task that needs to be locked

package com.huazai.aiyou.controller.task.schedu;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 
 * @author HuaZai
 * @contact who.seek.me@java98k.vip
 *          <ul>
 * @description TODO
 *              </ul>
 * @className TaskSchedulerController
 * @package com.huazai.aiyou
 * @createdTime 2019 March 20, 2003
 *
 * @version V1.0.0
 */
@RestController
@Slf4j
public class TaskSchedulerController extends BaseController
{

	// TODO

	/**
	 * 
	 * @author HuaZai
	 * @contact who.seek.me@java98k.vip
	 * @title sendItemInfoMessage
	 *        <ul>
	 * @description TODO
	 *              </ul>
	 * @createdTime 2019 March 20, 2003
	 * @throws GlobalException
	 * @return void
	 *
	 * @version : V1.0.0
	 */
	@Scheduled(cron = "0 0 0 * * ?")
	@SchedulerLock(name = "sendItemInfoMessage")
	public void sendItemInfoMessage() throws GlobalException
	{
		try
		{
			// TODO
		} catch (Exception e)
		{
			throw new GlobalException(ExceptionCode.global.ITEM_FAIL, ParamContext.NONE_ITEM_INFO);
		}
	}

}

 

Parameter description:

@SchedulerLock role: Only methods with this annotation added to a method will be locked, and the library will ignore all other scheduled tasks.A name must be specified for the lock so that only one task with the same name can be executed at the same time to achieve the desired lock purpose.

parameter type describe
name             String               Used to label the name of a timer service, used to write to the database as an identity to distinguish different services, and if there are multiple timer tasks with the same name, only one of them succeeds at the same point in time.Default is: ""
lockAtMostFor              long

The maximum time, in milliseconds, that a node that successfully executes a task can have an exclusive lock.The default value is: -1L, which means it is not valid, but only when set to a positive integer.

This property mainly specifies how long the lock should be held if the executing node dies.This is just a contingency plan. Normally, locks are released when the task is completed, even if the node dies, after which time a set value is released to avoid deadlocks.However, lockAtMostFormust be set to a value much longer than normal execution time, depending on your own judgment of the task.If the task spends more time than lockAtMostFortime, the results may be unpredictable (especially when multiple processes will hold locks effectively).

lockAtMostForString String String expression for the maximum time an exclusive lock can be owned by a node that successfully executes a task.For example, "PT30S" means 30 seconds; and "PT10M" means 14 minutes.
lockAtLeastFor long

The minimum exclusive time a node can successfully execute a task in milliseconds ms.The default value is: -1L, which means it is not valid, but only when set to a positive integer.

The lockAtLeastForproperty specifies the minimum time value for which locks should be retained. Its main purpose is to solve the problem of short task execution time and time differences between nodes when multiple nodes execute (e.g., 18:00 for A node and 18:08 for B node, when the time difference is 8 minutes, so this time is because lockAtLeastFor>=8M is specified to ensure the sameTasks are executed only once in this period, not more than once.

lockAtLeastForString String String expression for the shortest time an exclusive lock can be owned by a node that successfully executes a task.For example, "PT30S" means 30 seconds; and "PT10M" means 14 minutes.

 

@EnableSchedulerLock Role: Turn on ShedLock support

interceptMode Default is: EnableSchedulerLock.InterceptMode.PROXY_METHOD
defaultLockAtMostFor               The string representation of the maximum time an exclusive lock can be owned by a node that successfully executes a task, such as "PT30S" for 30 seconds
defaultLockAtLeastFor The string representation of the shortest time an exclusive lock can be owned by a node that successfully executes a task, such as "PT30S" for 30 seconds, defaulting to "PT0S"
mode Default is: AdviceMode.PROXY
proxyTargetClass Default is:false

 

*Note: By setting lockAtMostFor, we can ensure that the lock is released properly even if the node dies; by setting lockAtLeastFor, we can ensure that it does not execute more than once in a specified time.Note that lockAtMostForis only a safe range for node execution in case of node death, so this time needs to be set much longer than the maximum evaluation task execution time.If a task takes longer to execute than the lockAtMostFors you set up, it may execute again so that the same task executes repeatedly, resulting in unpredictable results (resulting in more processes holding locks).

 

5. Two modes of Spring integrated ShedLock

ShedLock supports two Spring integration modes.One is to use the AOP proxy (PROXY_METHOD) about the scheduling method, and the other is to use the proxy task scheduler (PROXY_SCHEDULER), as shown below:

 

As for ShedLock's integration mode, the default values are usually used. If you know about it, you can stop writing here and visit the official website for interested partners.

 

 

 

Reference:

ShedLock GitHub documentation: https://github.com/lukas-krecan/ShedLock

Well, here's a detailed explanation of using SpringBoot2.x Integrated Lightweight Distributed Timer Task ShedLock3.x. If you have any questions or questions, you can also leave me a message. I'll answer them in detail.(
Episode: "Learn together and make progress together", I also hope you pay more attention to the IT community of CSND.

By: Hua Keizi
Contact author: who.seek.me@java98k.vip
Source: CSDN (Chinese Software Developer Network)
Original: https://blog.csdn.net/Hello_World_QWP/article/details/103710853
Copyright Statement: This article is an original blogger article, please make sure to indicate the source of the blog when you reproduce it!

 

319 original articles were published, 643 were praised, and 1.48 million visits were received.
His message board follow

Tags: JDBC Spring Database Redis

Posted on Wed, 05 Feb 2020 20:57:34 -0500 by dwu