Add Redis lock periodic renewal
Although `RenewableLockRegistry` provides a renew interface, it is inconvenient for users. Developers hope to have a lock that can be automatically renewed. On the one hand, it can avoid subsequent failures caused by locks that will not expire when abnormal exits, and on the other hand, it can avoid unlock failures caused by lock expired. * Add `RenewableLockRegistry.setRenewalTaskScheduler()` and when it is set, schedule a `renew()` script periodically when lock is acquired from Redis with `1/3` of `expireAfter` * Test and document the feature
This commit is contained in:
@@ -51,8 +51,10 @@ import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.integration.redis.RedisContainerTest;
|
||||
import org.springframework.integration.redis.util.RedisLockRegistry.RedisLockType;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -66,6 +68,7 @@ import static org.mockito.Mockito.mock;
|
||||
* @author Artem Vozhdayenko
|
||||
* @author Anton Gabov
|
||||
* @author Eddie Cho
|
||||
* @author Youbin Wu
|
||||
*
|
||||
* @since 4.0
|
||||
*
|
||||
@@ -427,6 +430,20 @@ class RedisLockRegistryTests implements RedisContainerTest {
|
||||
registry.destroy();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(RedisLockType.class)
|
||||
void testRenewalOnExpire(RedisLockType redisLockType) throws Exception {
|
||||
long expireAfter = 300L;
|
||||
RedisLockRegistry registry = new RedisLockRegistry(redisConnectionFactory, this.registryKey, expireAfter);
|
||||
registry.setRenewalTaskScheduler(new SimpleAsyncTaskScheduler());
|
||||
registry.setRedisLockType(redisLockType);
|
||||
Lock lock1 = registry.obtain("foo");
|
||||
assertThat(lock1.tryLock()).isTrue();
|
||||
Thread.sleep(expireAfter * 2);
|
||||
lock1.unlock();
|
||||
registry.destroy();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(RedisLockType.class)
|
||||
void testEquals(RedisLockType testRedisLockType) {
|
||||
@@ -900,6 +917,33 @@ class RedisLockRegistryTests implements RedisContainerTest {
|
||||
registry.destroy();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(RedisLockType.class)
|
||||
void testLockRenew(RedisLockType redisLockType) {
|
||||
final RedisLockRegistry registry = new RedisLockRegistry(redisConnectionFactory, this.registryKey);
|
||||
registry.setRedisLockType(redisLockType);
|
||||
final Lock lock = registry.obtain("foo");
|
||||
|
||||
assertThat(lock.tryLock()).isTrue();
|
||||
try {
|
||||
registry.renewLock("foo");
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(RedisLockType.class)
|
||||
void testLockRenewLockNotOwned(RedisLockType redisLockType) {
|
||||
final RedisLockRegistry registry = new RedisLockRegistry(redisConnectionFactory, this.registryKey);
|
||||
registry.setRedisLockType(redisLockType);
|
||||
registry.obtain("foo");
|
||||
|
||||
assertThatExceptionOfType(IllegalStateException.class)
|
||||
.isThrownBy(() -> registry.renewLock("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitialiseWithCustomExecutor() {
|
||||
RedisLockRegistry redisLockRegistry = new RedisLockRegistry(redisConnectionFactory, "registryKey");
|
||||
|
||||
Reference in New Issue
Block a user