Skip to content

Commit a556866

Browse files
shawkinsmanusa
authored andcommitted
fix #3271: refining the wait logic
the only time to retry is on http gone delete does not need special handling in the watcher
1 parent bde7b96 commit a556866

File tree

6 files changed

+11
-99
lines changed

6 files changed

+11
-99
lines changed

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/WatcherException.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,4 @@ public boolean isHttpGone() {
3939
|| (cause.getStatus() != null && cause.getStatus().getCode() == HttpURLConnection.HTTP_GONE);
4040
}
4141

42-
public boolean isShouldRetry() {
43-
return getCause() == null || !isHttpGone();
44-
}
4542
}

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/Waitable.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public interface Waitable<T, P> {
3333
* @param backoffUnit the TimeUnit for the initial backoff value
3434
* @param backoffMultiplier what to multiply the backoff by on each subsequent error
3535
* @return the waitable
36+
* @deprecated no longer used
3637
*/
38+
@Deprecated
3739
Waitable<T, P> withWaitRetryBackoff(long initialBackoff, TimeUnit backoffUnit, double backoffMultiplier);
3840
}

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/BaseOperation.java

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import io.fabric8.kubernetes.client.informers.impl.DefaultSharedIndexInformer;
6060
import io.fabric8.kubernetes.client.internal.readiness.Readiness;
6161
import io.fabric8.kubernetes.client.utils.HttpClientUtils;
62+
import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
6263
import io.fabric8.kubernetes.client.utils.URLUtils;
6364
import io.fabric8.kubernetes.client.utils.Utils;
6465
import io.fabric8.kubernetes.client.utils.WatcherToggle;
@@ -123,8 +124,6 @@ public class BaseOperation<T extends HasMetadata, L extends KubernetesResourceLi
123124
private final boolean reloadingFromServer;
124125
private final long gracePeriodSeconds;
125126
private final DeletionPropagation propagationPolicy;
126-
private final long watchRetryInitialBackoffMillis;
127-
private final double watchRetryBackoffMultiplier;
128127

129128
protected String apiVersion;
130129

@@ -146,8 +145,6 @@ protected BaseOperation(OperationContext ctx) {
146145
this.labelsNotIn = ctx.getLabelsNotIn();
147146
this.fields = ctx.getFields();
148147
this.fieldsNot = ctx.getFieldsNot();
149-
this.watchRetryInitialBackoffMillis = ctx.getWatchRetryInitialBackoffMillis();
150-
this.watchRetryBackoffMultiplier = ctx.getWatchRetryBackoffMultiplier();
151148
}
152149

153150
public BaseOperation<T, L, R> newInstance(OperationContext context) {
@@ -1126,42 +1123,27 @@ public T waitUntilReady(long amount, TimeUnit timeUnit) throws InterruptedExcept
11261123
@Override
11271124
public T waitUntilCondition(Predicate<T> condition, long amount, TimeUnit timeUnit)
11281125
throws InterruptedException {
1129-
return waitUntilConditionWithRetries(condition, timeUnit.toNanos(amount), watchRetryInitialBackoffMillis);
1130-
}
1131-
1132-
private T waitUntilConditionWithRetries(Predicate<T> condition, long timeoutNanos, long backoffMillis)
1133-
throws InterruptedException {
1134-
ListOptions options = null;
11351126

1136-
if (resourceVersion != null) {
1137-
options = createListOptions(resourceVersion);
1138-
}
1139-
1140-
long currentBackOff = backoffMillis;
1141-
long remainingNanosToWait = timeoutNanos;
1127+
long remainingNanosToWait = timeUnit.toNanos(amount);
11421128
while (remainingNanosToWait > 0) {
11431129

11441130
T item = fromServer().get();
11451131
if (condition.test(item)) {
11461132
return item;
1147-
} else if (options == null) {
1148-
options = createListOptions(getResourceVersion(item));
11491133
}
11501134

11511135
final WaitForConditionWatcher<T> watcher = new WaitForConditionWatcher<>(condition);
11521136
final long startTime = System.nanoTime();
1153-
try (Watch ignored = watch(options, watcher)) {
1137+
try (Watch ignored = watch(KubernetesResourceUtil.getResourceVersion(item), watcher)) {
11541138
return watcher.getFuture().get(remainingNanosToWait, NANOSECONDS);
11551139
} catch (ExecutionException e) {
11561140
Throwable cause = e.getCause();
1157-
if (cause instanceof WatcherException && ((WatcherException) cause).isShouldRetry()) {
1158-
LOG.debug("retryable watch exception encountered, retrying after {} millis", currentBackOff, cause);
1159-
Thread.sleep(currentBackOff);
1160-
currentBackOff *= watchRetryBackoffMultiplier;
1141+
if (cause instanceof WatcherException && ((WatcherException)cause).isHttpGone()) {
1142+
LOG.debug("Restarting the watch due to http gone");
11611143
remainingNanosToWait -= (System.nanoTime() - startTime);
1162-
} else {
1163-
throw KubernetesClientException.launderThrowable(cause);
1144+
continue;
11641145
}
1146+
throw KubernetesClientException.launderThrowable(cause);
11651147
} catch (TimeoutException e) {
11661148
break;
11671149
}
@@ -1171,16 +1153,6 @@ private T waitUntilConditionWithRetries(Predicate<T> condition, long timeoutNano
11711153
throw new IllegalArgumentException(type.getSimpleName() + " with name:[" + name + "] in namespace:[" + namespace + "] matching condition not found!");
11721154
}
11731155

1174-
private static String getResourceVersion(HasMetadata item) {
1175-
return (item == null) ? null : item.getMetadata().getResourceVersion();
1176-
}
1177-
1178-
private static ListOptions createListOptions(String resourceVersion) {
1179-
return new ListOptionsBuilder()
1180-
.withResourceVersion(resourceVersion)
1181-
.build();
1182-
}
1183-
11841156
public void setType(Class<T> type) {
11851157
this.type = type;
11861158
}

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/base/WaitForConditionWatcher.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ public void eventReceived(Action action, T resource) {
4848
case DELETED:
4949
if (condition.test(null)) {
5050
future.complete(null);
51-
} else {
52-
future.completeExceptionally(new WatcherException("Unexpected deletion of watched resource, will never satisfy condition"));
5351
}
5452
break;
5553
case ERROR:

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/RawRequestBuilder.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

kubernetes-client/src/test/java/io/fabric8/kubernetes/client/dsl/base/WaitForConditionWatcherTest.java

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,11 @@ void itDoesNotCompleteOnNoMatchModified() {
9393
}
9494

9595
@Test
96-
void itCompletesExceptionallyOnUnexpectedDeletion() throws Exception {
96+
void itNotDeleted() throws Exception {
9797
TrackingPredicate condition = condition(Objects::nonNull);
9898
WaitForConditionWatcher<ConfigMap> watcher = new WaitForConditionWatcher<>(condition);
9999
watcher.eventReceived(Action.DELETED, configMap);
100-
assertTrue(watcher.getFuture().isDone());
101-
try {
102-
watcher.getFuture().get();
103-
fail("should have thrown exception");
104-
} catch (ExecutionException e) {
105-
assertEquals(WatcherException.class, e.getCause().getClass());
106-
assertEquals("Unexpected deletion of watched resource, will never satisfy condition", e.getCause().getMessage());
107-
}
108-
assertTrue(condition.isCalledWith(null));
100+
assertFalse(watcher.getFuture().isDone());
109101
}
110102

111103
@Test
@@ -136,7 +128,6 @@ void itCompletesExceptionallyWithRetryOnCloseNonGone() throws Exception {
136128
} catch (ExecutionException e) {
137129
assertEquals(WatcherException.class, e.getCause().getClass());
138130
assertEquals("Watcher closed", e.getCause().getMessage());
139-
assertTrue(((WatcherException) e.getCause()).isShouldRetry());
140131
}
141132
assertFalse(condition.isCalled());
142133
}
@@ -153,7 +144,6 @@ void itCompletesExceptionallyWithNoRetryOnCloseGone() throws Exception {
153144
} catch (ExecutionException e) {
154145
assertEquals(WatcherException.class, e.getCause().getClass());
155146
assertEquals("Watcher closed", e.getCause().getMessage());
156-
assertFalse(((WatcherException) e.getCause()).isShouldRetry());
157147
}
158148
assertFalse(condition.isCalled());
159149
}
@@ -170,7 +160,6 @@ void itCompletesExceptionallyWithRetryOnGracefulClose() throws Exception {
170160
} catch (ExecutionException e) {
171161
assertEquals(WatcherException.class, e.getCause().getClass());
172162
assertEquals("Watcher closed", e.getCause().getMessage());
173-
assertTrue(((WatcherException) e.getCause()).isShouldRetry());
174163
}
175164
assertFalse(condition.isCalled());
176165
}

0 commit comments

Comments
 (0)