Skip to content

Commit e268d73

Browse files
committed
feat: adding context to error handler; using exception instead runtime exception
1 parent dc0b621 commit e268d73

File tree

15 files changed

+93
-73
lines changed

15 files changed

+93
-73
lines changed

micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ public <T> T timeControllerExecution(ControllerExecution<T> execution) {
3333
.publishPercentileHistogram()
3434
.register(registry);
3535
try {
36-
final var result = timer.record(execution::execute);
36+
final var result = timer.record(() -> {
37+
try {
38+
return execution.execute();
39+
} catch (Exception e) {
40+
throw new IllegalStateException(e);
41+
}
42+
});
3743
final var successType = execution.successTypeName(result);
3844
registry
3945
.counter(execName + ".success", "controller", name, "type", successType)
@@ -72,7 +78,7 @@ public void finishedReconciliation(ResourceID resourceID) {
7278
incrementCounter(resourceID, RECONCILIATIONS + "success");
7379
}
7480

75-
public void failedReconciliation(ResourceID resourceID, RuntimeException exception) {
81+
public void failedReconciliation(ResourceID resourceID, Exception exception) {
7682
var cause = exception.getCause();
7783
if (cause == null) {
7884
cause = exception;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ default void receivedEvent(Event event) {}
1313

1414
default void reconcileCustomResource(ResourceID resourceID, RetryInfo retryInfo) {}
1515

16-
default void failedReconciliation(ResourceID resourceID, RuntimeException exception) {}
16+
default void failedReconciliation(ResourceID resourceID, Exception exception) {}
1717

1818
default void cleanupDoneFor(ResourceID customResourceUid) {}
1919

@@ -27,10 +27,10 @@ interface ControllerExecution<T> {
2727

2828
String successTypeName(T result);
2929

30-
T execute();
30+
T execute() throws Exception;
3131
}
3232

33-
default <T> T timeControllerExecution(ControllerExecution<T> execution) {
33+
default <T> T timeControllerExecution(ControllerExecution<T> execution) throws Exception {
3434
return execution.execute();
3535
}
3636

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
public class DefaultContext<P extends HasMetadata> implements Context<P> {
1111

12-
private final RetryInfo retryInfo;
12+
private RetryInfo retryInfo;
1313
private final Controller<P> controller;
1414
private final P primaryResource;
1515
private final ControllerConfiguration<P> controllerConfiguration;
@@ -44,4 +44,9 @@ public ControllerConfiguration<P> getControllerConfiguration() {
4444
public ManagedDependentResourceContext managedDependentResourceContext() {
4545
return managedDependentResourceContext;
4646
}
47+
48+
public DefaultContext<P> setRetryInfo(RetryInfo retryInfo) {
49+
this.retryInfo = retryInfo;
50+
return this;
51+
}
4752
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
66

7-
public interface ErrorStatusHandler<T extends HasMetadata> {
7+
public interface ErrorStatusHandler<P extends HasMetadata> {
88

99
/**
1010
* <p>
1111
* Reconciler can implement this interface in order to update the status sub-resource in the case
1212
* an exception in thrown. In that case
13-
* {@link #updateErrorStatus(HasMetadata, RetryInfo, RuntimeException)} is called automatically.
13+
* {@link #updateErrorStatus(HasMetadata, Context, Exception)} is called automatically.
1414
* <p>
1515
* The result of the method call is used to make a status update on the custom resource. This is
1616
* always a sub-resource update request, so no update on custom resource itself (like spec of
@@ -21,10 +21,10 @@ public interface ErrorStatusHandler<T extends HasMetadata> {
2121
* should not be updates on custom resource after it is marked for deletion.
2222
*
2323
* @param resource to update the status on
24-
* @param retryInfo the current retry status
24+
* @param context the current contex
2525
* @param e exception thrown from the reconciler
2626
* @return the updated resource
2727
*/
28-
Optional<T> updateErrorStatus(T resource, RetryInfo retryInfo, RuntimeException e);
28+
Optional<P> updateErrorStatus(P resource, Context<P> context, Exception e);
2929

3030
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public interface Reconciler<R extends HasMetadata> {
1313
* @return UpdateControl to manage updates on the custom resource (usually the status) after
1414
* reconciliation.
1515
*/
16-
UpdateControl<R> reconcile(R resource, Context<R> context);
16+
UpdateControl<R> reconcile(R resource, Context<R> context) throws Exception;
1717

1818
/**
1919
* Note that this method is used in combination with finalizers. If automatic finalizer handling

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

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,32 +64,36 @@ public Controller(Reconciler<P> reconciler,
6464
public DeleteControl cleanup(P resource, Context<P> context) {
6565
dependents.cleanup(resource, context);
6666

67-
return metrics().timeControllerExecution(
68-
new ControllerExecution<>() {
69-
@Override
70-
public String name() {
71-
return "cleanup";
72-
}
67+
try {
68+
return metrics().timeControllerExecution(
69+
new ControllerExecution<>() {
70+
@Override
71+
public String name() {
72+
return "cleanup";
73+
}
7374

74-
@Override
75-
public String controllerName() {
76-
return configuration.getName();
77-
}
75+
@Override
76+
public String controllerName() {
77+
return configuration.getName();
78+
}
7879

79-
@Override
80-
public String successTypeName(DeleteControl deleteControl) {
81-
return deleteControl.isRemoveFinalizer() ? "delete" : "finalizerNotRemoved";
82-
}
80+
@Override
81+
public String successTypeName(DeleteControl deleteControl) {
82+
return deleteControl.isRemoveFinalizer() ? "delete" : "finalizerNotRemoved";
83+
}
8384

84-
@Override
85-
public DeleteControl execute() {
86-
return reconciler.cleanup(resource, context);
87-
}
88-
});
85+
@Override
86+
public DeleteControl execute() {
87+
return reconciler.cleanup(resource, context);
88+
}
89+
});
90+
} catch (Exception e) {
91+
throw new IllegalStateException(e);
92+
}
8993
}
9094

9195
@Override
92-
public UpdateControl<P> reconcile(P resource, Context<P> context) {
96+
public UpdateControl<P> reconcile(P resource, Context<P> context) throws Exception {
9397
dependents.reconcile(resource, context);
9498

9599
return metrics().timeControllerExecution(
@@ -117,7 +121,7 @@ public String successTypeName(UpdateControl<P> result) {
117121
}
118122

119123
@Override
120-
public UpdateControl<P> execute() {
124+
public UpdateControl<P> execute() throws Exception {
121125
return reconciler.reconcile(resource, context);
122126
}
123127
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ TimerEventSource<R> retryEventSource() {
248248
* according to the retry timing if there was an exception.
249249
*/
250250
private void handleRetryOnException(
251-
ExecutionScope<R> executionScope, RuntimeException exception) {
251+
ExecutionScope<R> executionScope, Exception exception) {
252252
RetryExecution execution = getOrInitRetryExecution(executionScope);
253253
var customResourceID = executionScope.getCustomResourceID();
254254
boolean eventPresent = eventMarker.eventPresent(customResourceID);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ final class PostExecutionControl<R extends HasMetadata> {
88

99
private final boolean onlyFinalizerHandled;
1010
private final R updatedCustomResource;
11-
private final RuntimeException runtimeException;
11+
private final Exception runtimeException;
1212

1313
private Long reScheduleDelay = null;
1414

1515
private PostExecutionControl(
1616
boolean onlyFinalizerHandled,
1717
R updatedCustomResource,
18-
RuntimeException runtimeException) {
18+
Exception runtimeException) {
1919
this.onlyFinalizerHandled = onlyFinalizerHandled;
2020
this.updatedCustomResource = updatedCustomResource;
2121
this.runtimeException = runtimeException;
@@ -35,7 +35,7 @@ public static <R extends HasMetadata> PostExecutionControl<R> customResourceUpda
3535
}
3636

3737
public static <R extends HasMetadata> PostExecutionControl<R> exceptionDuringExecution(
38-
RuntimeException exception) {
38+
Exception exception) {
3939
return new PostExecutionControl<>(false, null, exception);
4040
}
4141

@@ -60,7 +60,7 @@ public PostExecutionControl<R> withReSchedule(long delay) {
6060
return this;
6161
}
6262

63-
public Optional<RuntimeException> getRuntimeException() {
63+
public Optional<Exception> getRuntimeException() {
6464
return Optional.ofNullable(runtimeException);
6565
}
6666

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ public ReconciliationDispatcher(Controller<R> controller) {
4848
public PostExecutionControl<R> handleExecution(ExecutionScope<R> executionScope) {
4949
try {
5050
return handleDispatch(executionScope);
51-
} catch (RuntimeException e) {
51+
} catch (Exception e) {
5252
log.error("Error during event processing {} failed.", executionScope, e);
5353
return PostExecutionControl.exceptionDuringExecution(e);
5454
}
5555
}
5656

57-
private PostExecutionControl<R> handleDispatch(ExecutionScope<R> executionScope) {
57+
private PostExecutionControl<R> handleDispatch(ExecutionScope<R> executionScope)
58+
throws Exception {
5859
R resource = executionScope.getResource();
5960
log.debug("Handling dispatch for resource {}", getName(resource));
6061

@@ -67,7 +68,7 @@ private PostExecutionControl<R> handleDispatch(ExecutionScope<R> executionScope)
6768
return PostExecutionControl.defaultDispatch();
6869
}
6970

70-
Context context = new DefaultContext<>(executionScope.getRetryInfo(), controller, resource);
71+
Context<R> context = new DefaultContext<>(executionScope.getRetryInfo(), controller, resource);
7172
if (markedForDeletion) {
7273
return handleCleanup(resource, context);
7374
} else {
@@ -91,7 +92,7 @@ private boolean shouldNotDispatchToDelete(R resource) {
9192
}
9293

9394
private PostExecutionControl<R> handleReconcile(
94-
ExecutionScope<R> executionScope, R originalResource, Context context) {
95+
ExecutionScope<R> executionScope, R originalResource, Context<R> context) throws Exception {
9596
if (configuration().useFinalizer()
9697
&& !originalResource.hasFinalizer(configuration().getFinalizer())) {
9798
/*
@@ -105,9 +106,9 @@ private PostExecutionControl<R> handleReconcile(
105106
} else {
106107
try {
107108
var resourceForExecution =
108-
cloneResourceForErrorStatusHandlerIfNeeded(originalResource, context);
109+
cloneResourceForErrorStatusHandlerIfNeeded(originalResource);
109110
return reconcileExecution(executionScope, resourceForExecution, originalResource, context);
110-
} catch (RuntimeException e) {
111+
} catch (Exception e) {
111112
handleErrorStatusHandler(originalResource, context, e);
112113
throw e;
113114
}
@@ -121,7 +122,7 @@ private PostExecutionControl<R> handleReconcile(
121122
* resource is changed during an execution, and it's much cleaner to have to original resource in
122123
* place for status update.
123124
*/
124-
private R cloneResourceForErrorStatusHandlerIfNeeded(R resource, Context context) {
125+
private R cloneResourceForErrorStatusHandlerIfNeeded(R resource) {
125126
if (isErrorStatusHandlerPresent() ||
126127
shouldUpdateObservedGenerationAutomatically(resource)) {
127128
final var configurationService = configuration().getConfigurationService();
@@ -133,7 +134,7 @@ private R cloneResourceForErrorStatusHandlerIfNeeded(R resource, Context context
133134
}
134135

135136
private PostExecutionControl<R> reconcileExecution(ExecutionScope<R> executionScope,
136-
R resourceForExecution, R originalResource, Context context) {
137+
R resourceForExecution, R originalResource, Context<R> context) throws Exception {
137138
log.debug(
138139
"Reconciling resource {} with version: {} with execution scope: {}",
139140
getName(resourceForExecution),
@@ -164,7 +165,7 @@ && shouldUpdateObservedGenerationAutomatically(resourceForExecution)) {
164165
}
165166

166167
private void handleErrorStatusHandler(R resource, Context<R> context,
167-
RuntimeException e) {
168+
Exception e) {
168169
if (isErrorStatusHandlerPresent()) {
169170
try {
170171
RetryInfo retryInfo = context.getRetryInfo().orElse(new RetryInfo() {
@@ -178,8 +179,9 @@ public boolean isLastAttempt() {
178179
return controller.getConfiguration().getRetryConfiguration() == null;
179180
}
180181
});
182+
((DefaultContext<R>) context).setRetryInfo(retryInfo);
181183
var updatedResource = ((ErrorStatusHandler<R>) controller.getReconciler())
182-
.updateErrorStatus(resource, retryInfo, e);
184+
.updateErrorStatus(resource, context, e);
183185
updatedResource.ifPresent(customResourceFacade::updateStatus);
184186
} catch (RuntimeException ex) {
185187
log.error("Error during error status handling.", ex);

0 commit comments

Comments
 (0)