diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d951050132..100913c8a29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### 6.3-SNAPSHOT #### Bugs +Fix #4547: preventing timing issues with leader election cancel #### Improvements diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElector.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElector.java index a4ec329ca71..b580389b655 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElector.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElector.java @@ -50,6 +50,7 @@ public class LeaderElector { private final AtomicReference observedRecord = new AtomicReference<>(); private final AtomicReference observedTime = new AtomicReference<>(); private final Executor executor; + private boolean stopped; public LeaderElector(KubernetesClient kubernetesClient, LeaderElectionConfig leaderElectionConfig, Executor executor) { this.kubernetesClient = kubernetesClient; @@ -110,7 +111,8 @@ public CompletableFuture start() { return result; } - private void stopLeading() { + private synchronized void stopLeading() { + stopped = true; LeaderElectionRecord current = observedRecord.get(); if (current == null || !isLeader(current)) { return; // not leading @@ -182,7 +184,10 @@ private CompletableFuture renewWithTimeout() { }, () -> leaderElectionConfig.getRetryPeriod().toMillis(), executor); } - boolean tryAcquireOrRenew() throws LockException { + synchronized boolean tryAcquireOrRenew() throws LockException { + if (stopped) { + return false; + } final Lock lock = leaderElectionConfig.getLock(); final ZonedDateTime now = now(); final LeaderElectionRecord oldLeaderElectionRecord = lock.get(kubernetesClient); diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElectorTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElectorTest.java index 39f3239c88a..3fef88737ef 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElectorTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/LeaderElectorTest.java @@ -134,6 +134,8 @@ void shouldReleaseWhenCanceled() throws Exception { Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> Utils.isNullOrEmpty(activeLer.get().getHolderIdentity())); assertEquals(0, activeLer.get().getLeaderTransitions()); + // create a new elector, they are no good after a single use + leaderElector = new LeaderElector(mock(NamespacedKubernetesClient.class), lec, CommonThreadPool.get()); // the leader is now empty/null, we should be able to re-acquire assertTrue(leaderElector.tryAcquireOrRenew());