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
This commit is contained in:
Artem Bilan
2018-04-17 17:05:09 -04:00
parent 50b1116e5f
commit 9c0a628f78
2 changed files with 46 additions and 5 deletions

View File

@@ -347,9 +347,16 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
}
catch (Exception e) {
if (this.locked) {
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
.unlock();
this.locked = false;
try {
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
.unlock();
}
catch (Exception e1) {
logger.debug("Could not unlock - treat as broken. " +
"Revoking " + (isRunning() ? " and retrying..." : "..."), e);
}
// The lock was broken and we are no longer leader
handleRevoked();
if (isRunning()) {
@@ -375,12 +382,17 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
}
finally {
if (this.locked) {
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
.unlock();
this.locked = false;
try {
LockRegistryLeaderInitiator.this.locks.obtain(this.lockKey)
.unlock();
}
catch (Exception e) {
logger.debug("Could not unlock during stop - treat as broken. Revoking...", e);
}
// We are stopping, therefore not leading any more
handleRevoked();
}
this.locked = false;
}
return null;
}

View File

@@ -163,6 +163,35 @@ public class JdbcLockRegistryLeaderInitiatorTests {
initiator1.stop();
}
@Test
public void testLostConnection() throws InterruptedException {
CountDownLatch granted = new CountDownLatch(1);
CountingPublisher countingPublisher = new CountingPublisher(granted);
DefaultLockRepository lockRepository = new DefaultLockRepository(dataSource);
lockRepository.afterPropertiesSet();
LockRegistryLeaderInitiator initiator = new LockRegistryLeaderInitiator(new JdbcLockRegistry(lockRepository));
initiator.setLeaderEventPublisher(countingPublisher);
initiator.start();
assertThat(granted.await(10, TimeUnit.SECONDS), is(true));
destroy();
assertThat(countingPublisher.revoked.await(10, TimeUnit.SECONDS), is(true));
granted = new CountDownLatch(1);
countingPublisher = new CountingPublisher(granted);
initiator.setLeaderEventPublisher(countingPublisher);
init();
assertThat(granted.await(10, TimeUnit.SECONDS), is(true));
initiator.stop();
}
private static class CountingPublisher implements LeaderEventPublisher {
private CountDownLatch granted;