Skip to content

Commit 6653eda

Browse files
committed
Convinient API to re-schedule events for UpdateControl
1 parent 0494505 commit 6653eda

File tree

6 files changed

+75
-17
lines changed

6 files changed

+75
-17
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/UpdateControl.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package io.javaoperatorsdk.operator.api;
22

3+
import java.util.Optional;
4+
import java.util.concurrent.TimeUnit;
5+
36
import io.fabric8.kubernetes.client.CustomResource;
47

58
public class UpdateControl<T extends CustomResource> {
69

710
private final T customResource;
811
private final boolean updateStatusSubResource;
912
private final boolean updateCustomResource;
13+
private Long reScheduleDelay = null;
1014

1115
private UpdateControl(
1216
T customResource, boolean updateStatusSubResource, boolean updateCustomResource) {
@@ -40,6 +44,19 @@ public static <T extends CustomResource> UpdateControl<T> noUpdate() {
4044
return new UpdateControl<>(null, false, false);
4145
}
4246

47+
public UpdateControl withReSchedule(long delay, TimeUnit timeUnit) {
48+
return withReSchedule(timeUnit.toMillis(delay));
49+
}
50+
51+
public UpdateControl withReSchedule(long delay) {
52+
this.reScheduleDelay = delay;
53+
return this;
54+
}
55+
56+
public Optional<Long> getReScheduleDelay() {
57+
return Optional.ofNullable(reScheduleDelay);
58+
}
59+
4360
public T getCustomResource() {
4461
return customResource;
4562
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,21 @@ void eventProcessingFinished(
163163
cleanupAfterDeletedEvent(executionScope.getCustomResourceUid());
164164
} else {
165165
cacheUpdatedResourceIfChanged(executionScope, postExecutionControl);
166+
reScheduleExecutionIfInstructed(postExecutionControl, executionScope.getCustomResource());
166167
executeBufferedEvents(executionScope.getCustomResourceUid());
167168
}
168169
} finally {
169170
lock.unlock();
170171
}
171172
}
172173

174+
private void reScheduleExecutionIfInstructed(PostExecutionControl<R> postExecutionControl,
175+
R customResource) {
176+
postExecutionControl.getReScheduleDelay().ifPresent(delay -> eventSourceManager
177+
.getRetryTimerEventSource()
178+
.scheduleOnce(customResource, delay));
179+
}
180+
173181
/**
174182
* Regarding the events there are 2 approaches we can take. Either retry always when there are new
175183
* events (received meanwhile retry is in place or already in buffer) instantly or always wait

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

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,20 @@ private PostExecutionControl<R> handleCreateOrUpdate(
140140
} else if (updateControl.isUpdateCustomResource()) {
141141
updatedCustomResource = updateCustomResource(updateControl.getCustomResource());
142142
}
143+
return createPostExecutionControl(updatedCustomResource, updateControl);
144+
}
145+
}
143146

144-
if (updatedCustomResource != null) {
145-
return PostExecutionControl.customResourceUpdated(updatedCustomResource);
146-
} else {
147-
return PostExecutionControl.defaultDispatch();
148-
}
147+
private PostExecutionControl<R> createPostExecutionControl(R updatedCustomResource,
148+
UpdateControl<R> updateControl) {
149+
PostExecutionControl<R> postExecutionControl;
150+
if (updatedCustomResource != null) {
151+
postExecutionControl = PostExecutionControl.customResourceUpdated(updatedCustomResource);
152+
} else {
153+
postExecutionControl = PostExecutionControl.defaultDispatch();
149154
}
155+
updateControl.getReScheduleDelay().ifPresent(postExecutionControl::withReSchedule);
156+
return postExecutionControl;
150157
}
151158

152159
private PostExecutionControl<R> handleDelete(R resource, Context<R> context) {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/PostExecutionControl.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
public final class PostExecutionControl<R extends CustomResource<?, ?>> {
88

99
private final boolean onlyFinalizerHandled;
10-
1110
private final R updatedCustomResource;
12-
1311
private final RuntimeException runtimeException;
1412

13+
private Long reScheduleDelay = null;
14+
1515
private PostExecutionControl(
1616
boolean onlyFinalizerHandled,
1717
R updatedCustomResource,
@@ -54,10 +54,19 @@ public boolean exceptionDuringExecution() {
5454
return runtimeException != null;
5555
}
5656

57+
public PostExecutionControl withReSchedule(long delay) {
58+
this.reScheduleDelay = delay;
59+
return this;
60+
}
61+
5762
public Optional<RuntimeException> getRuntimeException() {
5863
return Optional.ofNullable(runtimeException);
5964
}
6065

66+
public Optional<Long> getReScheduleDelay() {
67+
return Optional.ofNullable(reScheduleDelay);
68+
}
69+
6170
@Override
6271
public String toString() {
6372
return "PostExecutionControl{"

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/DefaultEventHandlerTest.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,7 @@
2323
import static io.javaoperatorsdk.operator.TestUtils.testCustomResource;
2424
import static org.assertj.core.api.Assertions.assertThat;
2525
import static org.mockito.ArgumentMatchers.eq;
26-
import static org.mockito.Mockito.any;
27-
import static org.mockito.Mockito.doAnswer;
28-
import static org.mockito.Mockito.doCallRealMethod;
29-
import static org.mockito.Mockito.mock;
30-
import static org.mockito.Mockito.never;
31-
import static org.mockito.Mockito.timeout;
32-
import static org.mockito.Mockito.times;
33-
import static org.mockito.Mockito.verify;
34-
import static org.mockito.Mockito.when;
26+
import static org.mockito.Mockito.*;
3527

3628
class DefaultEventHandlerTest {
3729

@@ -187,7 +179,6 @@ public void successfulExecutionResetsTheRetry() {
187179
Event event = prepareCREvent();
188180
TestCustomResource customResource = testCustomResource();
189181
customResource.getMetadata().setUid(event.getRelatedCustomResourceUid());
190-
ExecutionScope executionScope = new ExecutionScope(Arrays.asList(event), customResource, null);
191182
PostExecutionControl postExecutionControlWithException =
192183
PostExecutionControl.exceptionDuringExecution(new RuntimeException("test"));
193184
PostExecutionControl defaultDispatchControl = PostExecutionControl.defaultDispatch();
@@ -222,6 +213,18 @@ public void successfulExecutionResetsTheRetry() {
222213
assertThat(executionScopes.get(1).getRetryInfo().isLastAttempt()).isEqualTo(false);
223214
}
224215

216+
@Test
217+
public void scheduleTimedEventIfInstructedByPostExecutionControl() {
218+
var testDelay = 10000l;
219+
when(eventDispatcherMock.handleExecution(any()))
220+
.thenReturn(PostExecutionControl.defaultDispatch().withReSchedule(testDelay));
221+
222+
defaultEventHandler.handleEvent(prepareCREvent());
223+
224+
verify(retryTimerEventSourceMock, timeout(SEPARATE_EXECUTION_TIMEOUT).times(1))
225+
.scheduleOnce(any(), eq(testDelay));
226+
}
227+
225228
private void waitMinimalTime() {
226229
try {
227230
Thread.sleep(50);

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,20 @@ public boolean isLastAttempt() {
289289
assertThat(retryInfo.isLastAttempt()).isEqualTo(true);
290290
}
291291

292+
@Test
293+
void setReScheduleToPostExecutionControlFromUpdateControl() {
294+
testCustomResource.addFinalizer(DEFAULT_FINALIZER);
295+
296+
when(controller.createOrUpdateResource(eq(testCustomResource), any()))
297+
.thenReturn(
298+
UpdateControl.updateStatusSubResource(testCustomResource).withReSchedule(1000l));
299+
300+
PostExecutionControl control = eventDispatcher.handleExecution(
301+
executionScopeWithCREvent(Watcher.Action.ADDED, testCustomResource));
302+
303+
assertThat(control.getReScheduleDelay().get()).isEqualTo(1000l);
304+
}
305+
292306
private void markForDeletion(CustomResource customResource) {
293307
customResource.getMetadata().setDeletionTimestamp("2019-8-10");
294308
}

0 commit comments

Comments
 (0)