diff --git a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java index cadbae5f..0b10396b 100644 --- a/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java +++ b/spring-cloud-kubernetes-lock/src/main/java/org/springframework/cloud/kubernetes/lock/KubernetesLock.java @@ -22,7 +22,7 @@ import java.util.concurrent.locks.Lock; public class KubernetesLock implements Lock { - private static final int RETRY_PERIOD = 100; + private static final int LOCK_RETRY_INTERVAL = 100; private final ConfigMapLockRepository repository; @@ -47,7 +47,7 @@ public class KubernetesLock implements Lock { if (repository.create(name, holder, expiration)) { return; } - Thread.sleep(RETRY_PERIOD); + Thread.sleep(LOCK_RETRY_INTERVAL); } catch (InterruptedException e) { // This method cannot be interrupted } @@ -56,7 +56,18 @@ public class KubernetesLock implements Lock { @Override public void lockInterruptibly() throws InterruptedException { - // TODO same as lock(), but thread can be interrupted + repository.deleteIfExpired(name); + while (true) { + try { + if (repository.create(name, holder, expiration)) { + return; + } + Thread.sleep(LOCK_RETRY_INTERVAL); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw e; + } + } } @Override diff --git a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java index 30c4e49e..8dd7ee23 100644 --- a/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java +++ b/spring-cloud-kubernetes-lock/src/test/java/org/springframework/cloud/kubernetes/lock/KubernetesLockTest.java @@ -33,15 +33,8 @@ public class KubernetesLockTest { } @Test - public void shouldWaitUntilLockCanBeAcquired() { - given(repository.create(NAME, HOLDER, 0)).will(new Answer() { - private int callsCounter = 0; - - @Override - public Boolean answer(InvocationOnMock invocationOnMock) { - return callsCounter++ > 0; - } - }); + public void lockShouldWaitUntilLockCanBeAcquired() { + given(repository.create(NAME, HOLDER, 0)).will(new LockInSecondCall()); KubernetesLock lock = new KubernetesLock(repository, NAME, HOLDER, 0); lock.lock(); @@ -52,17 +45,7 @@ public class KubernetesLockTest { @Test public void lockShouldNotBeInterrupted() { - given(repository.create(NAME, HOLDER, 0)).will(new Answer() { - private int callsCounter = 0; - - @Override - public Boolean answer(InvocationOnMock invocationOnMock) throws InterruptedException { - if (callsCounter++ > 0) { - return true; - } - throw new InterruptedException("test exception"); - } - }); + given(repository.create(NAME, HOLDER, 0)).will(new InterrupFirstCall()); KubernetesLock lock = new KubernetesLock(repository, NAME, HOLDER, 0); lock.lock(); @@ -72,13 +55,33 @@ public class KubernetesLockTest { } @Test - public void shouldLockWithLockInterruptibly() { + public void shouldLockWithLockInterruptibly() throws InterruptedException { + given(repository.create(NAME, HOLDER, 0)).willReturn(true); + KubernetesLock lock = new KubernetesLock(repository, NAME, HOLDER, 0); + lock.lockInterruptibly(); + + verify(repository).deleteIfExpired(NAME); + verify(repository).create(NAME, HOLDER, 0); } @Test - public void lockInterruptiblyShouldBeInterrupted() { + public void lockInterruptiblyShouldWaitUntilLockCanBeAcquired() throws InterruptedException { + given(repository.create(NAME, HOLDER, 0)).will(new LockInSecondCall()); + KubernetesLock lock = new KubernetesLock(repository, NAME, HOLDER, 0); + lock.lockInterruptibly(); + + verify(repository).deleteIfExpired(NAME); + verify(repository, times(2)).create(NAME, HOLDER, 0); + } + + @Test(expected = InterruptedException.class) + public void lockInterruptiblyShouldBeInterrupted() throws InterruptedException { + given(repository.create(NAME, HOLDER, 0)).will(new InterrupFirstCall()); + + KubernetesLock lock = new KubernetesLock(repository, NAME, HOLDER, 0); + lock.lockInterruptibly(); } @Test @@ -107,4 +110,25 @@ public class KubernetesLockTest { lock.newCondition(); } + private static class LockInSecondCall implements Answer { + private int callsCounter = 0; + + @Override + public Boolean answer(InvocationOnMock invocationOnMock) { + return callsCounter++ > 0; + } + } + + private static class InterrupFirstCall implements Answer { + private int callsCounter = 0; + + @Override + public Boolean answer(InvocationOnMock invocationOnMock) throws InterruptedException { + if (callsCounter++ > 0) { + return true; + } + throw new InterruptedException("test exception"); + } + } + }