Skip to content

Commit c8deb6a

Browse files
committed
feat: adding context to error handler; using exception instead runtime exception
1 parent 6c8affc commit c8deb6a

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
@@ -60,32 +60,36 @@ public Controller(Reconciler<P> reconciler,
6060
public DeleteControl cleanup(P resource, Context<P> context) {
6161
dependents.cleanup(resource, context);
6262

63-
return metrics().timeControllerExecution(
64-
new ControllerExecution<>() {
65-
@Override
66-
public String name() {
67-
return "cleanup";
68-
}
63+
try {
64+
return metrics().timeControllerExecution(
65+
new ControllerExecution<>() {
66+
@Override
67+
public String name() {
68+
return "cleanup";
69+
}
6970

70-
@Override
71-
public String controllerName() {
72-
return configuration.getName();
73-
}
71+
@Override
72+
public String controllerName() {
73+
return configuration.getName();
74+
}
7475

75-
@Override
76-
public String successTypeName(DeleteControl deleteControl) {
77-
return deleteControl.isRemoveFinalizer() ? "delete" : "finalizerNotRemoved";
78-
}
76+
@Override
77+
public String successTypeName(DeleteControl deleteControl) {
78+
return deleteControl.isRemoveFinalizer() ? "delete" : "finalizerNotRemoved";
79+
}
7980

80-
@Override
81-
public DeleteControl execute() {
82-
return reconciler.cleanup(resource, context);
83-
}
84-
});
81+
@Override
82+
public DeleteControl execute() {
83+
return reconciler.cleanup(resource, context);
84+
}
85+
});
86+
} catch (Exception e) {
87+
throw new IllegalStateException(e);
88+
}
8589
}
8690

8791
@Override
88-
public UpdateControl<P> reconcile(P resource, Context<P> context) {
92+
public UpdateControl<P> reconcile(P resource, Context<P> context) throws Exception {
8993
dependents.reconcile(resource, context);
9094

9195
return metrics().timeControllerExecution(
@@ -113,7 +117,7 @@ public String successTypeName(UpdateControl<P> result) {
113117
}
114118

115119
@Override
116-
public UpdateControl<P> execute() {
120+
public UpdateControl<P> execute() throws Exception {
117121
return reconciler.reconcile(resource, context);
118122
}
119123
});

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
@@ -242,7 +242,7 @@ TimerEventSource<R> retryEventSource() {
242242
* according to the retry timing if there was an exception.
243243
*/
244244
private void handleRetryOnException(
245-
ExecutionScope<R> executionScope, RuntimeException exception) {
245+
ExecutionScope<R> executionScope, Exception exception) {
246246
RetryExecution execution = getOrInitRetryExecution(executionScope);
247247
var customResourceID = executionScope.getCustomResourceID();
248248
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 cloner = ConfigurationServiceProvider.instance().getResourceCloner();
@@ -132,7 +133,7 @@ private R cloneResourceForErrorStatusHandlerIfNeeded(R resource, Context context
132133
}
133134

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

165166
@SuppressWarnings("unchecked")
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)