LockRegistryLeaderInitiatorTests race condition

There is tiny time window when `LockRegistryLeaderInitiator` can be stopped during `Context.yield()` invocation.
In this case the `LockRegistryLeaderInitiator` goes to the stopped state, but a new `leaderSelector` is submitted for election.

Therefore in the `LockRegistryLeaderInitiatorTests.competing()` the second initiator may not get be granted because there is uncontrolled `leaderSelector` task on background.

We can overcome it with always `this.initiator.stop()` for the `LockRegistryLeaderInitiatorTests`, but to be sure in the fix it would be better to leave as is.

Also add `@Rule Log4jLevelAdjuster` for future diagnostics

**Cherry-pick to 4.3.x**
This commit is contained in:
Artem Bilan
2016-12-27 14:09:03 -05:00
parent f7b1ec8885
commit 56929cdae7
2 changed files with 21 additions and 9 deletions

View File

@@ -200,7 +200,9 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
*/
@Override
public boolean isRunning() {
return this.running;
synchronized (this.lifecycleMonitor) {
return this.running;
}
}
@Override
@@ -399,9 +401,11 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
public void yield() {
if (LockRegistryLeaderInitiator.this.future != null) {
LockRegistryLeaderInitiator.this.future.cancel(true);
LockRegistryLeaderInitiator.this.future =
LockRegistryLeaderInitiator.this.executorService
.submit(LockRegistryLeaderInitiator.this.leaderSelector);
if (isRunning()) {
LockRegistryLeaderInitiator.this.future =
LockRegistryLeaderInitiator.this.executorService
.submit(LockRegistryLeaderInitiator.this.leaderSelector);
}
}
}

View File

@@ -22,7 +22,9 @@ import static org.junit.Assert.assertThat;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Level;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.integration.leader.Context;
@@ -30,27 +32,33 @@ import org.springframework.integration.leader.DefaultCandidate;
import org.springframework.integration.leader.event.LeaderEventPublisher;
import org.springframework.integration.support.locks.DefaultLockRegistry;
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.integration.test.rule.Log4jLevelAdjuster;
/**
* @author Dave Syer
* @author Artem Bilan
*
* @since 4.3.1
*/
public class LockRegistryLeaderInitiatorTests {
private CountDownLatch granted = new CountDownLatch(1);
@Rule
public Log4jLevelAdjuster adjuster = new Log4jLevelAdjuster(Level.TRACE, "org.springframework.integration");
private CountDownLatch revoked = new CountDownLatch(1);
private CountDownLatch granted;
private CountDownLatch revoked;
private LockRegistry registry = new DefaultLockRegistry();
private CountingPublisher publisher = new CountingPublisher(this.granted, this.revoked);
private LockRegistryLeaderInitiator initiator =
new LockRegistryLeaderInitiator(this.registry, new DefaultCandidate());
@Before
public void init() {
this.initiator.setLeaderEventPublisher(this.publisher);
this.granted = new CountDownLatch(1);
this.revoked = new CountDownLatch(1);
this.initiator.setLeaderEventPublisher(new CountingPublisher(this.granted, this.revoked));
}
@Test