Skip to content

Commit 1a6ad39

Browse files
lburgazzolimetacosm
authored andcommitted
fix: stop timers when closing TimerEventSources
1 parent 2538aa4 commit 1a6ad39

File tree

2 files changed

+51
-5
lines changed

2 files changed

+51
-5
lines changed

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

+29-5
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,28 @@
33
import io.fabric8.kubernetes.client.CustomResource;
44
import io.javaoperatorsdk.operator.processing.KubernetesResourceUtils;
55
import io.javaoperatorsdk.operator.processing.event.AbstractEventSource;
6+
import java.io.IOException;
67
import java.util.Map;
78
import java.util.Timer;
89
import java.util.TimerTask;
910
import java.util.concurrent.ConcurrentHashMap;
11+
import java.util.concurrent.atomic.AtomicBoolean;
1012
import org.slf4j.Logger;
1113
import org.slf4j.LoggerFactory;
1214

1315
public class TimerEventSource extends AbstractEventSource {
1416

15-
private Logger log = LoggerFactory.getLogger(TimerEventSource.class);
16-
1717
private final Timer timer = new Timer();
18-
18+
private final AtomicBoolean running = new AtomicBoolean();
1919
private final Map<String, EventProducerTimeTask> onceTasks = new ConcurrentHashMap<>();
2020
private final Map<String, EventProducerTimeTask> timerTasks = new ConcurrentHashMap<>();
21+
private Logger log = LoggerFactory.getLogger(TimerEventSource.class);
2122

2223
public void schedule(CustomResource customResource, long delay, long period) {
24+
if (!running.get()) {
25+
throw new IllegalStateException("The TimerEventSource is not running");
26+
}
27+
2328
String resourceUid = KubernetesResourceUtils.getUID(customResource);
2429
if (timerTasks.containsKey(resourceUid)) {
2530
return;
@@ -30,6 +35,10 @@ public void schedule(CustomResource customResource, long delay, long period) {
3035
}
3136

3237
public void scheduleOnce(CustomResource customResource, long delay) {
38+
if (!running.get()) {
39+
throw new IllegalStateException("The TimerEventSource is not running");
40+
}
41+
3342
String resourceUid = KubernetesResourceUtils.getUID(customResource);
3443
if (onceTasks.containsKey(resourceUid)) {
3544
cancelOnceSchedule(resourceUid);
@@ -59,6 +68,19 @@ public void cancelOnceSchedule(String customResourceUid) {
5968
}
6069
}
6170

71+
@Override
72+
public void start() {
73+
running.set(true);
74+
}
75+
76+
@Override
77+
public void close() throws IOException {
78+
running.set(false);
79+
onceTasks.keySet().forEach(this::cancelOnceSchedule);
80+
timerTasks.keySet().forEach(this::cancelSchedule);
81+
timer.cancel();
82+
}
83+
6284
public class EventProducerTimeTask extends TimerTask {
6385

6486
protected final String customResourceUid;
@@ -69,8 +91,10 @@ public EventProducerTimeTask(String customResourceUid) {
6991

7092
@Override
7193
public void run() {
72-
log.debug("Producing event for custom resource id: {}", customResourceUid);
73-
eventHandler.handleEvent(new TimerEvent(customResourceUid, TimerEventSource.this));
94+
if (running.get()) {
95+
log.debug("Producing event for custom resource id: {}", customResourceUid);
96+
eventHandler.handleEvent(new TimerEvent(customResourceUid, TimerEventSource.this));
97+
}
7498
}
7599
}
76100
}

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

+22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID;
44
import static org.assertj.core.api.Assertions.assertThat;
5+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
56
import static org.mockito.Mockito.any;
67
import static org.mockito.Mockito.mock;
78
import static org.mockito.Mockito.never;
@@ -13,6 +14,7 @@
1314
import io.javaoperatorsdk.operator.TestUtils;
1415
import io.javaoperatorsdk.operator.processing.KubernetesResourceUtils;
1516
import io.javaoperatorsdk.operator.processing.event.EventHandler;
17+
import java.io.IOException;
1618
import java.util.List;
1719
import org.junit.jupiter.api.BeforeEach;
1820
import org.junit.jupiter.api.Disabled;
@@ -33,6 +35,7 @@ class TimerEventSourceTest {
3335
public void setup() {
3436
timerEventSource = new TimerEventSource();
3537
timerEventSource.setEventHandler(eventHandlerMock);
38+
timerEventSource.start();
3639
}
3740

3841
@Test
@@ -106,4 +109,23 @@ public void deRegistersOnceEventSources() throws InterruptedException {
106109

107110
verify(eventHandlerMock, never()).handleEvent(any());
108111
}
112+
113+
@Test
114+
public void eventNotRegisteredIfStopped() throws IOException {
115+
CustomResource customResource = TestUtils.testCustomResource();
116+
117+
timerEventSource.close();
118+
assertThatExceptionOfType(IllegalStateException.class).isThrownBy(
119+
() -> timerEventSource.scheduleOnce(customResource, PERIOD));
120+
}
121+
122+
@Test
123+
public void eventNotFiredIfStopped() throws InterruptedException, IOException {
124+
timerEventSource.scheduleOnce(TestUtils.testCustomResource(), PERIOD);
125+
timerEventSource.close();
126+
127+
Thread.sleep(PERIOD + TESTING_TIME_SLACK);
128+
129+
verify(eventHandlerMock, never()).handleEvent(any());
130+
}
109131
}

0 commit comments

Comments
 (0)