Skip to content

Commit 9c0a628

Browse files
committed
INT-4447: LockRegLeaderInit: Catch unlock errors
JIRA: https://jira.spring.io/browse/INT-4447 When we get an exception during `this.lock.unlock()`, we don't revoke leadership. In case of external resource (e.g. JDBC) this may cause a race condition when the second candidate is selected as leader when connection comes back * Catch `this.lock.unlock()` exceptions and log them under DEBUG. This way we proceed to the `handleRevoked()` logic **Cherry-pick to 5.0.x and 4.3.x** # Conflicts: # spring-integration-core/src/main/java/org/springframework/integration/support/leader/LockRegistryLeaderInitiator.java
1 parent 50b1116 commit 9c0a628

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

spring-integration-core/src/main/java/org/springframework/integration/support/leader/LockRegistryLeaderInitiator.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,16 @@ else if (acquired) {
347347
}
348348
catch (Exception e) {
349349
if (this.locked) {
350-
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
351-
.unlock();
352350
this.locked = false;
351+
try {
352+
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
353+
.unlock();
354+
}
355+
catch (Exception e1) {
356+
logger.debug("Could not unlock - treat as broken. " +
357+
"Revoking " + (isRunning() ? " and retrying..." : "..."), e);
358+
359+
}
353360
// The lock was broken and we are no longer leader
354361
handleRevoked();
355362
if (isRunning()) {
@@ -375,12 +382,17 @@ else if (logger.isDebugEnabled()) {
375382
}
376383
finally {
377384
if (this.locked) {
378-
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
379-
.unlock();
385+
this.locked = false;
386+
try {
387+
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
388+
.unlock();
389+
}
390+
catch (Exception e) {
391+
logger.debug("Could not unlock during stop - treat as broken. Revoking...", e);
392+
}
380393
// We are stopping, therefore not leading any more
381394
handleRevoked();
382395
}
383-
this.locked = false;
384396
}
385397
return null;
386398
}

spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/leader/JdbcLockRegistryLeaderInitiatorTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,35 @@ public void publishOnRevoked(Object source, Context context, String role) {
163163
initiator1.stop();
164164
}
165165

166+
@Test
167+
public void testLostConnection() throws InterruptedException {
168+
CountDownLatch granted = new CountDownLatch(1);
169+
CountingPublisher countingPublisher = new CountingPublisher(granted);
170+
171+
DefaultLockRepository lockRepository = new DefaultLockRepository(dataSource);
172+
lockRepository.afterPropertiesSet();
173+
LockRegistryLeaderInitiator initiator = new LockRegistryLeaderInitiator(new JdbcLockRegistry(lockRepository));
174+
initiator.setLeaderEventPublisher(countingPublisher);
175+
176+
initiator.start();
177+
178+
assertThat(granted.await(10, TimeUnit.SECONDS), is(true));
179+
180+
destroy();
181+
182+
assertThat(countingPublisher.revoked.await(10, TimeUnit.SECONDS), is(true));
183+
184+
granted = new CountDownLatch(1);
185+
countingPublisher = new CountingPublisher(granted);
186+
initiator.setLeaderEventPublisher(countingPublisher);
187+
188+
init();
189+
190+
assertThat(granted.await(10, TimeUnit.SECONDS), is(true));
191+
192+
initiator.stop();
193+
}
194+
166195
private static class CountingPublisher implements LeaderEventPublisher {
167196

168197
private CountDownLatch granted;

0 commit comments

Comments
 (0)