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:
@@ -200,7 +200,9 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return this.running;
|
synchronized (this.lifecycleMonitor) {
|
||||||
|
return this.running;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -399,9 +401,11 @@ public class LockRegistryLeaderInitiator implements SmartLifecycle, DisposableBe
|
|||||||
public void yield() {
|
public void yield() {
|
||||||
if (LockRegistryLeaderInitiator.this.future != null) {
|
if (LockRegistryLeaderInitiator.this.future != null) {
|
||||||
LockRegistryLeaderInitiator.this.future.cancel(true);
|
LockRegistryLeaderInitiator.this.future.cancel(true);
|
||||||
LockRegistryLeaderInitiator.this.future =
|
if (isRunning()) {
|
||||||
LockRegistryLeaderInitiator.this.executorService
|
LockRegistryLeaderInitiator.this.future =
|
||||||
.submit(LockRegistryLeaderInitiator.this.leaderSelector);
|
LockRegistryLeaderInitiator.this.executorService
|
||||||
|
.submit(LockRegistryLeaderInitiator.this.leaderSelector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ import static org.junit.Assert.assertThat;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.log4j.Level;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.integration.leader.Context;
|
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.leader.event.LeaderEventPublisher;
|
||||||
import org.springframework.integration.support.locks.DefaultLockRegistry;
|
import org.springframework.integration.support.locks.DefaultLockRegistry;
|
||||||
import org.springframework.integration.support.locks.LockRegistry;
|
import org.springframework.integration.support.locks.LockRegistry;
|
||||||
|
import org.springframework.integration.test.rule.Log4jLevelAdjuster;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Artem Bilan
|
||||||
|
*
|
||||||
* @since 4.3.1
|
* @since 4.3.1
|
||||||
*/
|
*/
|
||||||
public class LockRegistryLeaderInitiatorTests {
|
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 LockRegistry registry = new DefaultLockRegistry();
|
||||||
|
|
||||||
private CountingPublisher publisher = new CountingPublisher(this.granted, this.revoked);
|
|
||||||
|
|
||||||
private LockRegistryLeaderInitiator initiator =
|
private LockRegistryLeaderInitiator initiator =
|
||||||
new LockRegistryLeaderInitiator(this.registry, new DefaultCandidate());
|
new LockRegistryLeaderInitiator(this.registry, new DefaultCandidate());
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() {
|
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
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user