| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
`PollingEventSource` held its timer in a final field initialised at
construction:
private final Timer timer = new Timer();
Two problems follow from that.
The event source cannot be restarted. `stop()` calls `timer.cancel()` and
a cancelled `java.util.Timer` cannot be reused, so a subsequent `start()`
fails with `IllegalStateException: Timer already cancelled`. Restart is a
supported lifecycle - `Operator.stop()` / `start()` recreates the thread
pools for exactly this reason, and `TimerEventSource` creates a new
`Timer` inside `start()`.
The timer thread is not a daemon and is created eagerly. Merely
constructing a `PollingEventSource` therefore starts a non-daemon thread
that keeps the JVM from exiting, even if the event source is never
started, and it outlives an operator that is stopped without stopping its
event sources. `TimerEventSource` uses `new Timer(true)`.
The timer is now created in `start()` as a daemon and cleared in `stop()`,
matching `TimerEventSource`.
Adds regression tests for restart and for the daemon flag; the restart one
fails with `IllegalStateException: Timer already cancelled` without this
change.
Note: `PerResourcePollingEventSource` has a related restart limitation
because `stop()` calls `shutdownNow()` on the `ScheduledExecutorService`
from its configuration. That executor is supplied by the caller, so
changing its ownership semantics is a separate discussion and is left
out of this change.
There was a problem hiding this comment.
This PR fixes PollingEventSource lifecycle and JVM-exit behavior by moving java.util.Timer creation to start() (as a daemon) and clearing it in stop(), aligning its lifecycle with supported operator restart semantics and with TimerEventSource.
Changes:
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java | Timer lifecycle moved to start()/stop() and daemonized to support restart and avoid blocking JVM shutdown. |
| operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSourceTest.java | Adds regression coverage for restart behavior and daemon timer thread behavior. |
Sorry, something went wrong.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
LGTM
Sorry, something went wrong.
There was a problem hiding this comment.
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java:116
public void stop() throws OperatorException {
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/polling/PollingEventSource.java:84
This issue also appears on line 116 of the same file.
public void start() throws OperatorException {
if (timer != null) {
return;
}
super.start();
Sorry, something went wrong.
operator-framework#3523) `PollingEventSource` held its timer in a final field initialised at construction: private final Timer timer = new Timer(); Two problems follow from that. The event source cannot be restarted. `stop()` calls `timer.cancel()` and a cancelled `java.util.Timer` cannot be reused, so a subsequent `start()` fails with `IllegalStateException: Timer already cancelled`. Restart is a supported lifecycle - `Operator.stop()` / `start()` recreates the thread pools for exactly this reason, and `TimerEventSource` creates a new `Timer` inside `start()`. The timer thread is not a daemon and is created eagerly. Merely constructing a `PollingEventSource` therefore starts a non-daemon thread that keeps the JVM from exiting, even if the event source is never started, and it outlives an operator that is stopped without stopping its event sources. `TimerEventSource` uses `new Timer(true)`. The timer is now created in `start()` as a daemon and cleared in `stop()`, matching `TimerEventSource`. Adds regression tests for restart and for the daemon flag; the restart one fails with `IllegalStateException: Timer already cancelled` without this change. Note: `PerResourcePollingEventSource` has a related restart limitation because `stop()` calls `shutdownNow()` on the `ScheduledExecutorService` from its configuration. That executor is supplied by the caller, so changing its ownership semantics is a separate discussion and is left out of this change. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| Back | FazBrowse Home | New Git URL |
PollingEventSource held its timer in a final field initialised at
construction:
Two problems follow from that.
The event source cannot be restarted. stop() calls timer.cancel() and
a cancelled java.util.Timer cannot be reused, so a subsequent start()
fails with IllegalStateException: Timer already cancelled. Restart is a
supported lifecycle - Operator.stop() / start() recreates the thread
pools for exactly this reason, and TimerEventSource creates a new
Timer inside start().
The timer thread is not a daemon and is created eagerly. Merely
constructing a PollingEventSource therefore starts a non-daemon thread
that keeps the JVM from exiting, even if the event source is never
started, and it outlives an operator that is stopped without stopping its
event sources. TimerEventSource uses new Timer(true).
The timer is now created in start() as a daemon and cleared in stop(),
matching TimerEventSource.
Adds regression tests for restart and for the daemon flag; the restart one
fails with IllegalStateException: Timer already cancelled without this
change.
Note: PerResourcePollingEventSource has a related restart limitation
because stop() calls shutdownNow() on the ScheduledExecutorService
from its configuration. That executor is supplied by the caller, so
changing its ownership semantics is a separate discussion and is left
out of this change.
Part of #3517