Skip to content

Commit cbfd993

Browse files
authored
refactor!: replace Closeable by explicit LifecycleAware interface (#633)
This ensures that stoppable classes can also be started if needed. Fixes #629
1 parent 26cfdee commit cbfd993

File tree

13 files changed

+82
-67
lines changed

13 files changed

+82
-67
lines changed

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

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.javaoperatorsdk.operator;
22

3-
import java.io.Closeable;
4-
import java.io.IOException;
53
import java.net.ConnectException;
64
import java.util.ArrayList;
75
import java.util.HashMap;
@@ -15,14 +13,15 @@
1513
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
1614
import io.fabric8.kubernetes.client.KubernetesClient;
1715
import io.fabric8.kubernetes.client.Version;
16+
import io.javaoperatorsdk.operator.api.LifecycleAware;
1817
import io.javaoperatorsdk.operator.api.ResourceController;
1918
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
2019
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
2120
import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager;
2221
import io.javaoperatorsdk.operator.processing.ConfiguredController;
2322

2423
@SuppressWarnings("rawtypes")
25-
public class Operator implements AutoCloseable {
24+
public class Operator implements AutoCloseable, LifecycleAware {
2625
private static final Logger log = LoggerFactory.getLogger(Operator.class);
2726
private final KubernetesClient kubernetesClient;
2827
private final ConfigurationService configurationService;
@@ -90,18 +89,23 @@ public void start() {
9089
controllers.start();
9190
}
9291

93-
/** Stop the operator. */
9492
@Override
95-
public void close() {
93+
public void stop() throws OperatorException {
9694
log.info(
9795
"Operator SDK {} is shutting down...", configurationService.getVersion().getSdkVersion());
9896

99-
controllers.close();
97+
controllers.stop();
10098

101-
ExecutorServiceManager.close();
99+
ExecutorServiceManager.stop();
102100
kubernetesClient.close();
103101
}
104102

103+
/** Stop the operator. */
104+
@Override
105+
public void close() {
106+
stop();
107+
}
108+
105109
/**
106110
* Add a registration requests for the specified controller with this operator. The effective
107111
* registration of the controller is delayed till the operator is started.
@@ -159,7 +163,7 @@ public <R extends CustomResource> void register(
159163
}
160164
}
161165

162-
private static class ControllerManager implements Closeable {
166+
private static class ControllerManager implements LifecycleAware {
163167
private final Map<String, ConfiguredController> controllers = new HashMap<>();
164168
private boolean started = false;
165169

@@ -178,19 +182,14 @@ public synchronized void start() {
178182
started = true;
179183
}
180184

181-
@Override
182-
public synchronized void close() {
185+
public synchronized void stop() {
183186
if (!started) {
184187
return;
185188
}
186189

187190
this.controllers.values().parallelStream().forEach(closeable -> {
188-
try {
189-
log.debug("closing {}", closeable);
190-
closeable.close();
191-
} catch (IOException e) {
192-
log.warn("Error closing {}", closeable, e);
193-
}
191+
log.debug("closing {}", closeable);
192+
closeable.stop();
194193
});
195194

196195
started = false;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package io.javaoperatorsdk.operator.api;
2+
3+
import io.javaoperatorsdk.operator.OperatorException;
4+
5+
public interface LifecycleAware {
6+
void start() throws OperatorException;
7+
8+
void stop() throws OperatorException;
9+
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public static void init(ConfigurationService configuration) {
3434
}
3535
}
3636

37-
public static void close() {
37+
public static void stop() {
3838
if (instance != null) {
39-
instance.stop();
39+
instance.doStop();
4040
}
4141
// make sure that we remove the singleton so that the thread pool is re-created on next call to
4242
// start
@@ -55,7 +55,7 @@ public ExecutorService executorService() {
5555
return executor;
5656
}
5757

58-
private void stop() {
58+
private void doStop() {
5959
try {
6060
log.debug("Closing executor");
6161
executor.shutdown();

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

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

3-
import java.io.Closeable;
4-
import java.io.IOException;
53
import java.util.Objects;
64

75
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
@@ -13,14 +11,19 @@
1311
import io.javaoperatorsdk.operator.CustomResourceUtils;
1412
import io.javaoperatorsdk.operator.MissingCRDException;
1513
import io.javaoperatorsdk.operator.OperatorException;
16-
import io.javaoperatorsdk.operator.api.*;
14+
import io.javaoperatorsdk.operator.api.Context;
15+
import io.javaoperatorsdk.operator.api.DeleteControl;
16+
import io.javaoperatorsdk.operator.api.EventSourceInitializer;
17+
import io.javaoperatorsdk.operator.api.LifecycleAware;
18+
import io.javaoperatorsdk.operator.api.ResourceController;
19+
import io.javaoperatorsdk.operator.api.UpdateControl;
1720
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
1821
import io.javaoperatorsdk.operator.api.monitoring.Metrics.ControllerExecution;
1922
import io.javaoperatorsdk.operator.processing.event.DefaultEventSourceManager;
2023
import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
2124

2225
public class ConfiguredController<R extends CustomResource<?, ?>> implements ResourceController<R>,
23-
Closeable, EventSourceInitializer {
26+
LifecycleAware, EventSourceInitializer {
2427
private final ResourceController<R> controller;
2528
private final ControllerConfiguration<R> configuration;
2629
private final KubernetesClient kubernetesClient;
@@ -214,10 +217,9 @@ public EventSourceManager getEventSourceManager() {
214217
return eventSourceManager;
215218
}
216219

217-
@Override
218-
public void close() throws IOException {
220+
public void stop() {
219221
if (eventSourceManager != null) {
220-
eventSourceManager.close();
222+
eventSourceManager.stop();
221223
}
222224
}
223225
}

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

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

3-
import java.io.Closeable;
43
import java.util.HashMap;
54
import java.util.HashSet;
65
import java.util.Map;
@@ -14,11 +13,16 @@
1413
import org.slf4j.LoggerFactory;
1514

1615
import io.fabric8.kubernetes.client.CustomResource;
16+
import io.javaoperatorsdk.operator.OperatorException;
17+
import io.javaoperatorsdk.operator.api.LifecycleAware;
1718
import io.javaoperatorsdk.operator.api.RetryInfo;
1819
import io.javaoperatorsdk.operator.api.config.ConfigurationService;
1920
import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager;
2021
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
21-
import io.javaoperatorsdk.operator.processing.event.*;
22+
import io.javaoperatorsdk.operator.processing.event.CustomResourceID;
23+
import io.javaoperatorsdk.operator.processing.event.DefaultEventSourceManager;
24+
import io.javaoperatorsdk.operator.processing.event.Event;
25+
import io.javaoperatorsdk.operator.processing.event.EventHandler;
2226
import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEvent;
2327
import io.javaoperatorsdk.operator.processing.event.internal.ResourceAction;
2428
import io.javaoperatorsdk.operator.processing.retry.GenericRetry;
@@ -33,7 +37,7 @@
3337
* UID, while buffering events which are received during an execution.
3438
*/
3539
public class DefaultEventHandler<R extends CustomResource<?, ?>>
36-
implements EventHandler, Closeable {
40+
implements EventHandler, LifecycleAware {
3741

3842
private static final Logger log = LoggerFactory.getLogger(DefaultEventHandler.class);
3943

@@ -315,7 +319,7 @@ private boolean isRetryConfigured() {
315319
}
316320

317321
@Override
318-
public void close() {
322+
public void stop() {
319323
lock.lock();
320324
try {
321325
this.running = false;
@@ -324,6 +328,16 @@ public void close() {
324328
}
325329
}
326330

331+
@Override
332+
public void start() throws OperatorException {
333+
lock.lock();
334+
try {
335+
this.running = true;
336+
} finally {
337+
lock.unlock();
338+
}
339+
}
340+
327341
private class ControllerExecution implements Runnable {
328342
private final ExecutionScope<R> executionScope;
329343

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

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

3-
import java.io.Closeable;
4-
import java.util.*;
3+
import java.util.Collections;
4+
import java.util.HashSet;
5+
import java.util.Objects;
6+
import java.util.Set;
57
import java.util.concurrent.locks.ReentrantLock;
68

79
import org.slf4j.Logger;
@@ -10,13 +12,14 @@
1012
import io.fabric8.kubernetes.client.CustomResource;
1113
import io.javaoperatorsdk.operator.MissingCRDException;
1214
import io.javaoperatorsdk.operator.OperatorException;
15+
import io.javaoperatorsdk.operator.api.LifecycleAware;
1316
import io.javaoperatorsdk.operator.processing.ConfiguredController;
1417
import io.javaoperatorsdk.operator.processing.DefaultEventHandler;
1518
import io.javaoperatorsdk.operator.processing.event.internal.CustomResourceEventSource;
1619
import io.javaoperatorsdk.operator.processing.event.internal.TimerEventSource;
1720

1821
public class DefaultEventSourceManager<R extends CustomResource<?, ?>>
19-
implements EventSourceManager<R>, Closeable {
22+
implements EventSourceManager<R>, LifecycleAware {
2023

2124
private static final Logger log = LoggerFactory.getLogger(DefaultEventSourceManager.class);
2225

@@ -45,18 +48,23 @@ private void init(DefaultEventHandler<R> defaultEventHandler) {
4548
}
4649

4750
@Override
48-
public void close() {
51+
public void start() throws OperatorException {
52+
defaultEventHandler.start();
53+
}
54+
55+
@Override
56+
public void stop() {
4957
lock.lock();
5058
try {
5159
try {
52-
defaultEventHandler.close();
60+
defaultEventHandler.stop();
5361
} catch (Exception e) {
5462
log.warn("Error closing event handler", e);
5563
}
5664
log.debug("Closing event sources.");
5765
for (var eventSource : eventSources) {
5866
try {
59-
eventSource.close();
67+
eventSource.stop();
6068
} catch (Exception e) {
6169
log.warn("Error closing {} -> {}", eventSource, e);
6270
}

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

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,8 @@
11
package io.javaoperatorsdk.operator.processing.event;
22

3-
import java.io.Closeable;
4-
import java.io.IOException;
3+
import io.javaoperatorsdk.operator.api.LifecycleAware;
54

6-
public interface EventSource extends Closeable {
7-
8-
/**
9-
* This method is invoked when this {@link EventSource} instance is properly registered to a
10-
* {@link EventSourceManager}.
11-
*/
12-
default void start() {}
13-
14-
/**
15-
* This method is invoked when this {@link EventSource} instance is de-registered from a
16-
* {@link EventSourceManager}.
17-
*/
18-
@Override
19-
default void close() throws IOException {}
5+
public interface EventSource extends LifecycleAware {
206

217
void setEventHandler(EventHandler eventHandler);
228

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.javaoperatorsdk.operator.processing.event.internal;
22

3-
import java.io.IOException;
43
import java.util.*;
54
import java.util.concurrent.ConcurrentHashMap;
65

@@ -105,13 +104,13 @@ public void start() {
105104
}
106105

107106
@Override
108-
public void close() throws IOException {
107+
public void stop() {
109108
for (SharedIndexInformer<T> informer : sharedIndexInformers.values()) {
110109
try {
111-
log.info("Closing informer {} -> {}", controller, informer);
112-
informer.close();
110+
log.info("Stopping informer {} -> {}", controller, informer);
111+
informer.stop();
113112
} catch (Exception e) {
114-
log.warn("Error closing informer {} -> {}", controller, informer, e);
113+
log.warn("Error stopping informer {} -> {}", controller, informer, e);
115114
}
116115
}
117116
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.javaoperatorsdk.operator.processing.event.internal;
22

3-
import java.io.IOException;
43
import java.util.Objects;
54
import java.util.Set;
65
import java.util.function.Function;
@@ -93,7 +92,7 @@ public void start() {
9392
}
9493

9594
@Override
96-
public void close() throws IOException {
95+
public void stop() {
9796
sharedInformer.close();
9897
}
9998

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.javaoperatorsdk.operator.processing.event.internal;
22

3-
import java.io.IOException;
43
import java.util.Map;
54
import java.util.Timer;
65
import java.util.TimerTask;
@@ -76,7 +75,7 @@ public void start() {
7675
}
7776

7877
@Override
79-
public void close() throws IOException {
78+
public void stop() {
8079
running.set(false);
8180
onceTasks.keySet().forEach(this::cancelOnceSchedule);
8281
timerTasks.keySet().forEach(this::cancelSchedule);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ public void reScheduleOnlyIfNotExecutedBufferedEvents() {
194194

195195
@Test
196196
public void doNotFireEventsIfClosing() {
197-
defaultEventHandler.close();
197+
defaultEventHandler.stop();
198198
defaultEventHandler.handleEvent(prepareCREvent());
199199

200200
verify(eventDispatcherMock, timeout(50).times(0)).handleExecution(any());

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ public void closeShouldCascadeToEventSources() throws IOException {
4242
defaultEventSourceManager.registerEventSource(eventSource);
4343
defaultEventSourceManager.registerEventSource(eventSource2);
4444

45-
defaultEventSourceManager.close();
45+
defaultEventSourceManager.stop();
4646

47-
verify(eventSource, times(1)).close();
48-
verify(eventSource2, times(1)).close();
47+
verify(eventSource, times(1)).stop();
48+
verify(eventSource2, times(1)).stop();
4949
}
5050

5151
@Test

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/internal/TimerEventSourceTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,15 @@ public void deRegistersOnceEventSources() {
112112
public void eventNotRegisteredIfStopped() throws IOException {
113113
TestCustomResource customResource = TestUtils.testCustomResource();
114114

115-
timerEventSource.close();
115+
timerEventSource.stop();
116116
assertThatExceptionOfType(IllegalStateException.class).isThrownBy(
117117
() -> timerEventSource.scheduleOnce(customResource, PERIOD));
118118
}
119119

120120
@Test
121121
public void eventNotFiredIfStopped() throws IOException {
122122
timerEventSource.scheduleOnce(TestUtils.testCustomResource(), PERIOD);
123-
timerEventSource.close();
123+
timerEventSource.stop();
124124

125125
untilAsserted(() -> assertThat(eventHandlerMock.events).isEmpty());
126126
}

0 commit comments

Comments
 (0)