Skip to content

Commit 695e156

Browse files
authored
GH-3888: Fix NPE in the RedisLockRegistry.destroy() (#3889)
* GH-3888: Fix NPE in the `RedisLockRegistry.destroy()` Fixed #3888 When `RedisLockType.SPIN_LOCK` (default), the `RedisLockRegistry.destroy()` causes an NPE on the `redisMessageListenerContainer` since pub-sub is not used in a busy-spin mode * Check for `redisMessageListenerContainer` before calling its `destroy()` **Cherry-pick to 5.5.x** * * Reset properties in the `RedisLockRegistry` after `destroy()`
1 parent ab7b579 commit 695e156

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

spring-integration-redis/src/main/java/org/springframework/integration/redis/util/RedisLockRegistry.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,15 @@ public void destroy() {
245245
if (!this.executorExplicitlySet) {
246246
((ExecutorService) this.executor).shutdown();
247247
}
248-
try {
249-
this.redisMessageListenerContainer.destroy();
250-
}
251-
catch (Exception ex) {
252-
throw new IllegalStateException(ex);
248+
if (this.redisMessageListenerContainer != null) {
249+
try {
250+
this.redisMessageListenerContainer.destroy();
251+
this.redisMessageListenerContainer = null;
252+
this.isRunningRedisMessageListenerContainer = false;
253+
}
254+
catch (Exception ex) {
255+
throw new IllegalStateException(ex);
256+
}
253257
}
254258
}
255259

spring-integration-redis/src/test/java/org/springframework/integration/redis/util/RedisLockRegistryTests.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ void testLock(RedisLockType testRedisLockType) {
107107
}
108108
registry.expireUnusedOlderThan(-1000);
109109
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
110+
registry.destroy();
110111
}
111112

112113
@ParameterizedTest
@@ -126,6 +127,7 @@ void testLockInterruptibly(RedisLockType testRedisLockType) throws Exception {
126127
}
127128
registry.expireUnusedOlderThan(-1000);
128129
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
130+
registry.destroy();
129131
}
130132

131133
@ParameterizedTest
@@ -153,6 +155,7 @@ void testReentrantLock(RedisLockType testRedisLockType) {
153155
}
154156
registry.expireUnusedOlderThan(-1000);
155157
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
158+
registry.destroy();
156159
}
157160

158161
@ParameterizedTest
@@ -180,6 +183,7 @@ void testReentrantLockInterruptibly(RedisLockType testRedisLockType) throws Exce
180183
}
181184
registry.expireUnusedOlderThan(-1000);
182185
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
186+
registry.destroy();
183187
}
184188

185189
@ParameterizedTest
@@ -207,6 +211,7 @@ void testTwoLocks(RedisLockType testRedisLockType) throws Exception {
207211
}
208212
registry.expireUnusedOlderThan(-1000);
209213
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
214+
registry.destroy();
210215
}
211216

212217
@ParameterizedTest
@@ -238,6 +243,7 @@ void testTwoThreadsSecondFailsToGetLock(RedisLockType testRedisLockType) throws
238243
assertThat(((Exception) ise).getMessage()).contains("You do not own lock at");
239244
registry.expireUnusedOlderThan(-1000);
240245
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
246+
registry.destroy();
241247
}
242248

243249
@ParameterizedTest
@@ -277,6 +283,7 @@ void testTwoThreads(RedisLockType testRedisLockType) throws Exception {
277283
assertThat(locked.get()).isTrue();
278284
registry.expireUnusedOlderThan(-1000);
279285
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
286+
registry.destroy();
280287
}
281288

282289
@ParameterizedTest
@@ -326,6 +333,8 @@ void testTwoThreadsDifferentRegistries(RedisLockType testRedisLockType) throws E
326333
registry2.expireUnusedOlderThan(-1000);
327334
assertThat(getRedisLockRegistryLocks(registry1)).isEmpty();
328335
assertThat(getRedisLockRegistryLocks(registry2)).isEmpty();
336+
registry1.destroy();
337+
registry2.destroy();
329338
}
330339

331340
@ParameterizedTest
@@ -355,6 +364,7 @@ void testTwoThreadsWrongOneUnlocks(RedisLockType testRedisLockType) throws Excep
355364
assertThat(((Exception) ise).getMessage()).contains("You do not own lock at");
356365
registry.expireUnusedOlderThan(-1000);
357366
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
367+
registry.destroy();
358368
}
359369

360370
@ParameterizedTest
@@ -371,6 +381,8 @@ void testExpireTwoRegistries(RedisLockType testRedisLockType) throws Exception {
371381
waitForExpire("foo");
372382
assertThat(lock2.tryLock()).isTrue();
373383
assertThat(lock1.tryLock()).isFalse();
384+
registry1.destroy();
385+
registry2.destroy();
374386
}
375387

376388
@ParameterizedTest
@@ -384,6 +396,7 @@ void testExceptionOnExpire(RedisLockType testRedisLockType) throws Exception {
384396
assertThatIllegalStateException()
385397
.isThrownBy(lock1::unlock)
386398
.withMessageContaining("Lock was released in the store due to expiration.");
399+
registry.destroy();
387400
}
388401

389402

@@ -422,6 +435,9 @@ void testEquals(RedisLockType testRedisLockType) {
422435
lock2.lock();
423436
lock1.unlock();
424437
lock2.unlock();
438+
registry1.destroy();
439+
registry2.destroy();
440+
registry3.destroy();
425441
}
426442

427443
@ParameterizedTest
@@ -446,6 +462,7 @@ void testThreadLocalListLeaks(RedisLockType testRedisLockType) {
446462
lock.unlock();
447463
}
448464
assertThat(getRedisLockRegistryLocks(registry)).hasSize(10);
465+
registry.destroy();
449466
}
450467

451468
@ParameterizedTest
@@ -468,6 +485,7 @@ void testExpireNotChanged(RedisLockType testRedisLockType) throws Exception {
468485
result.get();
469486
assertThat(getExpire(registry, "foo")).isEqualTo(expire);
470487
lock.unlock();
488+
registry.destroy();
471489
}
472490

473491
@ParameterizedTest
@@ -510,6 +528,7 @@ void concurrentObtainCapacityTest(RedisLockType testRedisLockType) throws Interr
510528

511529
registry.expireUnusedOlderThan(-1000);
512530
assertThat(getRedisLockRegistryLocks(registry)).isEmpty();
531+
registry.destroy();
513532
}
514533

515534
@ParameterizedTest
@@ -558,7 +577,8 @@ void concurrentObtainRemoveOrderTest(RedisLockType testRedisLockType) throws Int
558577
executorService.awaitTermination(5, TimeUnit.SECONDS);
559578

560579
assertThat(getRedisLockRegistryLocks(registry)).containsKeys(
561-
remainLockCheckQueue.toArray(new String[remainLockCheckQueue.size()]));
580+
remainLockCheckQueue.toArray(new String[0]));
581+
registry.destroy();
562582
}
563583

564584
@ParameterizedTest
@@ -613,7 +633,8 @@ void concurrentObtainAccessRemoveOrderTest(RedisLockType testRedisLockType) thro
613633
executorService.awaitTermination(5, TimeUnit.SECONDS);
614634

615635
assertThat(getRedisLockRegistryLocks(registry)).containsKeys(
616-
remainLockCheckQueue.toArray(new String[remainLockCheckQueue.size()]));
636+
remainLockCheckQueue.toArray(new String[0]));
637+
registry.destroy();
617638
}
618639

619640
@ParameterizedTest
@@ -642,6 +663,7 @@ void setCapacityTest(RedisLockType testRedisLockType) {
642663
registry.obtain("foo:5");
643664
assertThat(getRedisLockRegistryLocks(registry)).hasSize(4);
644665
assertThat(getRedisLockRegistryLocks(registry)).containsKeys("foo:3", "foo:4", "foo:5");
666+
registry.destroy();
645667
}
646668

647669
@ParameterizedTest
@@ -690,6 +712,8 @@ void twoRedisLockRegistryTest(RedisLockType testRedisLockType) throws Interrupte
690712

691713
assertThat(future1).isNotCompletedExceptionally();
692714
assertThat(future2).isNotCompletedExceptionally();
715+
registry1.destroy();
716+
registry2.destroy();
693717
}
694718

695719
@ParameterizedTest
@@ -782,6 +806,9 @@ void earlyWakeUpTest(RedisLockType testRedisLockType) throws InterruptedExceptio
782806
assertThat(awaitTimeout.await(1, TimeUnit.SECONDS)).isFalse();
783807
assertThat(expectOne.get()).isEqualTo(1);
784808
executorService.shutdown();
809+
registry1.destroy();
810+
registry2.destroy();
811+
registry3.destroy();
785812
}
786813

787814
private Long getExpire(RedisLockRegistry registry, String lockKey) {

0 commit comments

Comments
 (0)