[
https://issues.apache.org/jira/browse/CAMEL-26334?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-26334 started by shashank.
----------------------------------------
> camel-once - the consumer keeps a non-daemon timer thread after its route or
> the CamelContext stopped, and a restarted route fails to start (Task already
> scheduled or cancelled)
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-26334
> URL: https://issues.apache.org/jira/browse/CAMEL-26334
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> {{OnceConsumer}} creates a {{java.util.Timer}} in its constructor ({{new
> Timer(endpoint.getName())}}, a non-daemon thread named after the endpoint)
> and never cancels it: {{doStop}} only cancels the {{TimerTask}} (main
> 8e0ce2d21371). So:
> * the thread stays alive after the route is stopped and after the
> CamelContext is stopped; after the route is removed it ends only when the
> consumer is garbage collected (the cleaner of {{java.util.Timer}}). Every
> once route that was created, or reloaded in dev mode, keeps a thread until
> then, and a non-daemon one;
> * a once route that is stopped and started again does not start: {{doStart}}
> schedules the cancelled {{TimerTask}} again and fails with
> {{IllegalStateException: Task already scheduled or cancelled}}. A
> CamelContext with a once route that is stopped and started again fails to
> start the same way, and so does the resume of a suspended once route.
> {code:java}
> from("once:tick?delay=0").routeId("r").process(e -> fired.release());
> context.start(); // fires
> context.stop(); // thread "tick" (non-daemon) still
> alive 10 s later
> // 20 routes from("once:xN?delay=0") added, fired, stopped and removed: 20
> threads alive 10 s later
> context.getRouteController().stopRoute("r");
> context.getRouteController().startRoute("r"); // IllegalStateException:
> Task already scheduled or cancelled
> {code}
> *Fix* (proposed): the consumer fires on a single thread scheduled executor
> that {{doStart}} creates through the {{ExecutorServiceManager}} (thread
> {{Camel (<context>) thread #N - <name>}}). {{doStop}} cancels the pending
> fire with {{cancel(false)}} (a fire that is routing is not interrupted, as
> with {{TimerTask.cancel()}}) and shuts the executor down. Each start
> schedules a new fire, so a restarted route fires again, as {{doStop}}
> resetting {{scheduled}} intended. {{scheduleTask(TimerTask, Timer)}} becomes
> {{scheduleTask()}}, which does nothing before the consumer started. This also
> takes the {{TimerTask}} out of camel-once, which CAMEL-22957 listed for
> virtual thread support. Upgrade guide entry (thread name, restart, protected
> method).
> *Tests*: {{OnceConsumerLifecycleTest}} (5 tests, latches and {{Thread.join}},
> no sleeps): the thread ends when the CamelContext stops; when the route is
> removed before it fired ({{delay=3600000}}); no thread left after 20 routes
> were added, fired and removed; a route started again fires again; a route
> fires again after a CamelContext restart. All 5 fail on main (3 with the
> leaked non-daemon threads listed, 2 with the IllegalStateException) and pass
> with the fix; camel-once 16/0.
> *How it was found*: a scan of the consumers for {{java.util.Timer}} and own
> executors that outlive a route stop, while adding leak invariants (no task of
> a pool after the route stop, pools released) to the deterministic simulation
> worlds; a {{java.util.Timer}} is outside the harness, so the scan and a plain
> test found it.
> *Affected*: 4.17.0 and later (4.17.x, 4.18.x, 4.22.x, 4.23.0, main; same code
> since the component was added in CAMEL-22431).
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)