Skip to content

Commit 10c97e1

Browse files
committed
retry improvements and tests
1 parent 115e44d commit 10c97e1

19 files changed

+358
-28
lines changed

operator-framework/src/main/java/io/javaoperatorsdk/operator/Operator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private <R extends CustomResource> void registerController(
8484
customResourceCache, eventDispatcher, controller.getClass().getName(), retry);
8585
DefaultEventSourceManager eventSourceManager =
8686
new DefaultEventSourceManager(defaultEventHandler, retry != null);
87-
defaultEventHandler.setDefaultEventSourceManager(eventSourceManager);
87+
defaultEventHandler.setEventSourceManager(eventSourceManager);
8888
eventDispatcher.setEventSourceManager(eventSourceManager);
8989

9090
customResourceClients.put(resClass, (CustomResourceOperationsImpl) client);

operator-framework/src/main/java/io/javaoperatorsdk/operator/api/Context.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import io.fabric8.kubernetes.client.CustomResource;
44
import io.javaoperatorsdk.operator.processing.event.EventList;
55
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
6+
import java.util.Optional;
67

78
public interface Context<T extends CustomResource> {
89

910
EventSourceManager getEventSourceManager();
1011

1112
EventList getEvents();
13+
14+
Optional<RetryInfo> getRetryInfo();
1215
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/api/DefaultContext.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import io.fabric8.kubernetes.client.CustomResource;
44
import io.javaoperatorsdk.operator.processing.event.EventList;
55
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
6+
import java.util.Optional;
67

78
public class DefaultContext<T extends CustomResource> implements Context<T> {
89

10+
private final RetryInfo retryInfo;
911
private final EventList events;
1012
private final EventSourceManager eventSourceManager;
1113

12-
public DefaultContext(EventSourceManager eventSourceManager, EventList events) {
14+
public DefaultContext(
15+
EventSourceManager eventSourceManager, EventList events, RetryInfo retryInfo) {
16+
this.retryInfo = retryInfo;
1317
this.events = events;
1418
this.eventSourceManager = eventSourceManager;
1519
}
@@ -23,4 +27,9 @@ public EventSourceManager getEventSourceManager() {
2327
public EventList getEvents() {
2428
return events;
2529
}
30+
31+
@Override
32+
public Optional<RetryInfo> getRetryInfo() {
33+
return Optional.ofNullable(retryInfo);
34+
}
2635
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/api/RetryInfo.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22

33
public class RetryInfo {
44

5-
private int retryNumber;
5+
private int attemptIndex;
66
private boolean lastAttempt;
77

88
public RetryInfo(int retryNumber, boolean lastAttempt) {
9-
this.retryNumber = retryNumber;
9+
this.attemptIndex = retryNumber;
1010
this.lastAttempt = lastAttempt;
1111
}
1212

13-
public int getRetryNumber() {
14-
return retryNumber;
13+
public int getAttemptIndex() {
14+
return attemptIndex;
1515
}
1616

1717
public boolean isLastAttempt() {
1818
return lastAttempt;
1919
}
20+
21+
@Override
22+
public String toString() {
23+
return "RetryInfo{" + "attemptIndex=" + attemptIndex + ", lastAttempt=" + lastAttempt + '}';
24+
}
2025
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/DefaultEventHandler.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion;
66

77
import io.fabric8.kubernetes.client.CustomResource;
8+
import io.javaoperatorsdk.operator.api.RetryInfo;
89
import io.javaoperatorsdk.operator.processing.event.DefaultEventSourceManager;
910
import io.javaoperatorsdk.operator.processing.event.Event;
1011
import io.javaoperatorsdk.operator.processing.event.EventHandler;
@@ -35,7 +36,7 @@ public class DefaultEventHandler implements EventHandler {
3536
private final EventDispatcher eventDispatcher;
3637
private final Retry retry;
3738
private final Map<String, RetryExecution> retryState = new HashMap<>();
38-
private DefaultEventSourceManager defaultEventSourceManager;
39+
private DefaultEventSourceManager eventSourceManager;
3940

4041
private final ReentrantLock lock = new ReentrantLock();
4142

@@ -59,8 +60,8 @@ public Thread newThread(Runnable runnable) {
5960
});
6061
}
6162

62-
public void setDefaultEventSourceManager(DefaultEventSourceManager defaultEventSourceManager) {
63-
this.defaultEventSourceManager = defaultEventSourceManager;
63+
public void setEventSourceManager(DefaultEventSourceManager eventSourceManager) {
64+
this.eventSourceManager = eventSourceManager;
6465
}
6566

6667
@Override
@@ -86,7 +87,8 @@ private void executeBufferedEvents(String customResourceUid) {
8687
ExecutionScope executionScope =
8788
new ExecutionScope(
8889
eventBuffer.getAndRemoveEventsForExecution(customResourceUid),
89-
latestCustomResource.get());
90+
latestCustomResource.get(),
91+
retryInfo(customResourceUid));
9092
log.debug("Executing events for custom resource. Scope: {}", executionScope);
9193
executor.execute(new ExecutionConsumer(executionScope, eventDispatcher, this));
9294
} else {
@@ -100,6 +102,15 @@ private void executeBufferedEvents(String customResourceUid) {
100102
}
101103
}
102104

105+
private RetryInfo retryInfo(String customResourceUid) {
106+
RetryExecution retryExecution = retryState.get(customResourceUid);
107+
if (retryExecution != null) {
108+
return new RetryInfo(retryExecution.getCurrentAttemptIndex(), retryExecution.isLastAttempt());
109+
} else {
110+
return null;
111+
}
112+
}
113+
103114
void eventProcessingFinished(
104115
ExecutionScope executionScope, PostExecutionControl postExecutionControl) {
105116
try {
@@ -143,14 +154,14 @@ private void handleRetryOnException(ExecutionScope executionScope) {
143154
Optional<Long> nextDelay = execution.nextDelay();
144155
nextDelay.ifPresent(
145156
delay ->
146-
defaultEventSourceManager
157+
eventSourceManager
147158
.getRetryTimerEventSource()
148159
.scheduleOnce(executionScope.getCustomResource(), delay));
149160
}
150161

151162
private void markSuccessfulExecutionRegardingRetry(ExecutionScope executionScope) {
152163
retryState.remove(executionScope.getCustomResourceUid());
153-
defaultEventSourceManager
164+
eventSourceManager
154165
.getRetryTimerEventSource()
155166
.cancelOnceSchedule(executionScope.getCustomResourceUid());
156167
}
@@ -200,7 +211,7 @@ private void cacheUpdatedResourceIfChanged(
200211
}
201212

202213
private void cleanupAfterDeletedEvent(String customResourceUid) {
203-
defaultEventSourceManager.cleanup(customResourceUid);
214+
eventSourceManager.cleanup(customResourceUid);
204215
eventBuffer.cleanup(customResourceUid);
205216
customResourceCache.cleanup(customResourceUid);
206217
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/EventDispatcher.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ private PostExecutionControl handleDispatch(ExecutionScope executionScope) {
6666
return PostExecutionControl.defaultDispatch();
6767
}
6868
Context context =
69-
new DefaultContext(eventSourceManager, new EventList(executionScope.getEvents()));
69+
new DefaultContext(
70+
eventSourceManager,
71+
new EventList(executionScope.getEvents()),
72+
executionScope.getRetryInfo());
7073
if (markedForDeletion(resource)) {
7174
return handleDelete(resource, context);
7275
} else {

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/ExecutionScope.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.javaoperatorsdk.operator.processing;
22

33
import io.fabric8.kubernetes.client.CustomResource;
4+
import io.javaoperatorsdk.operator.api.RetryInfo;
45
import io.javaoperatorsdk.operator.processing.event.Event;
56
import java.util.List;
67

@@ -10,9 +11,12 @@ public class ExecutionScope {
1011
// the latest custom resource from cache
1112
private CustomResource customResource;
1213

13-
public ExecutionScope(List<Event> list, CustomResource customResource) {
14+
private RetryInfo retryInfo;
15+
16+
public ExecutionScope(List<Event> list, CustomResource customResource, RetryInfo retryInfo) {
1417
this.events = list;
1518
this.customResource = customResource;
19+
this.retryInfo = retryInfo;
1620
}
1721

1822
public List<Event> getEvents() {
@@ -38,4 +42,8 @@ public String toString() {
3842
+ customResource.getMetadata().getResourceVersion()
3943
+ '}';
4044
}
45+
46+
public RetryInfo getRetryInfo() {
47+
return retryInfo;
48+
}
4149
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/retry/GenericRetryExecution.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ public Optional<Long> nextDelay() {
2929
}
3030

3131
@Override
32-
public boolean isLastExecution() {
32+
public boolean isLastAttempt() {
3333
return genericRetry.getMaxAttempts() > -1 && lastAttemptIndex >= genericRetry.getMaxAttempts();
3434
}
35+
36+
@Override
37+
public int getCurrentAttemptIndex() {
38+
return lastAttemptIndex;
39+
}
3540
}

operator-framework/src/main/java/io/javaoperatorsdk/operator/processing/retry/RetryExecution.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ public interface RetryExecution {
1616
* @return true, if the last returned delay is, the last returned values, thus there will be no
1717
* further retry
1818
*/
19-
boolean isLastExecution();
19+
boolean isLastAttempt();
20+
21+
int getCurrentAttemptIndex();
2022
}

operator-framework/src/test/java/io/javaoperatorsdk/operator/EventDispatcherTest.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package io.javaoperatorsdk.operator;
22

3+
import static org.assertj.core.api.Assertions.assertThat;
34
import static org.junit.jupiter.api.Assertions.assertEquals;
45
import static org.mockito.Mockito.*;
56

67
import io.fabric8.kubernetes.client.CustomResource;
78
import io.fabric8.kubernetes.client.Watcher;
8-
import io.javaoperatorsdk.operator.api.DeleteControl;
9-
import io.javaoperatorsdk.operator.api.ResourceController;
10-
import io.javaoperatorsdk.operator.api.UpdateControl;
9+
import io.javaoperatorsdk.operator.api.*;
1110
import io.javaoperatorsdk.operator.processing.EventDispatcher;
1211
import io.javaoperatorsdk.operator.processing.ExecutionScope;
1312
import io.javaoperatorsdk.operator.processing.event.Event;
@@ -18,6 +17,7 @@
1817
import java.util.List;
1918
import org.junit.jupiter.api.BeforeEach;
2019
import org.junit.jupiter.api.Test;
20+
import org.mockito.ArgumentCaptor;
2121
import org.mockito.ArgumentMatchers;
2222

2323
class EventDispatcherTest {
@@ -177,6 +177,20 @@ void executeControllerRegardlessGenerationInNonGenerationAwareMode() {
177177
verify(controller, times(2)).createOrUpdateResource(eq(testCustomResource), any());
178178
}
179179

180+
@Test
181+
void propagatesRetryInfoToContext() {
182+
eventDispatcher.handleExecution(
183+
new ExecutionScope(Arrays.asList(), testCustomResource, new RetryInfo(2, true)));
184+
185+
ArgumentCaptor<Context<CustomResource>> contextArgumentCaptor =
186+
ArgumentCaptor.forClass(Context.class);
187+
verify(controller, times(1))
188+
.createOrUpdateResource(eq(testCustomResource), contextArgumentCaptor.capture());
189+
Context<CustomResource> context = contextArgumentCaptor.getValue();
190+
assertThat(context.getRetryInfo().get().getAttemptIndex()).isEqualTo(2);
191+
assertThat(context.getRetryInfo().get().isLastAttempt()).isEqualTo(true);
192+
}
193+
180194
private void markForDeletion(CustomResource customResource) {
181195
customResource.getMetadata().setDeletionTimestamp("2019-8-10");
182196
}
@@ -191,6 +205,6 @@ public ExecutionScope executionScopeWithCREvent(
191205
List<Event> eventList = new ArrayList<>(1 + otherEvents.length);
192206
eventList.add(event);
193207
eventList.addAll(Arrays.asList(otherEvents));
194-
return new ExecutionScope(eventList, resource);
208+
return new ExecutionScope(eventList, resource, null);
195209
}
196210
}

0 commit comments

Comments
 (0)