[
https://issues.apache.org/jira/browse/CAMEL-25252?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Claus Ibsen resolved CAMEL-25252.
---------------------------------
Resolution: Fixed
Merged via https://github.com/apache/camel/pull/27249
> camel-timer - stopping a timer consumer with a negative delay releases the
> shared java.util.Timer it never took, which cancels the timer of the other
> routes with the same timer name (they stay Started but never fire again)
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25252
> URL: https://issues.apache.org/jira/browse/CAMEL-25252
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Assignee: shashank
> Priority: Minor
> Fix For: 4.23.0
>
>
> The timer consumers of the same timer name share one {{java.util.Timer}},
> which {{TimerComponent}} reference counts: {{getTimer}} creates it or
> increments the count (line numbers of main, :63-79), {{removeTimer}}
> decrements it and cancels the {{Timer}} at 0 (:81-92).
> {{TimerConsumer}} takes the reference only for a delay of 0 or more
> ({{doStart}} :181-186, or {{onCamelContextStarted}} :229-234 when the
> consumer was started before the context). A consumer with a negative delay
> ({{delay=-1}}, fire as fast as possible, CAMEL-9249) uses its own single
> thread executor (:190) and never calls {{getTimer}}. But {{doStop}} always
> calls {{endpoint.removeTimer(this)}} (:217). So stopping such a consumer
> decrements a count it never incremented. When it was the last reference of
> another consumer, the shared {{Timer}} is cancelled while that consumer is
> still running: its route stays Started but never fires again, and nothing is
> logged. Because the holder is removed from the map, a route started later on
> the same name gets a new {{Timer}}, but the running one is not rescheduled.
> Example: {{from("timer:tick?period=1000")}} in one route and
> {{from("timer:tick?delay=-1&repeatCount=1")}} in another (a one-shot start-up
> route). Stopping the second route (JMX, the route controller, a route policy,
> or a restart of it) silently stops the first.
> h3. Reproduction
> Route A {{timer:shared?period=20}}, route B
> {{timer:shared?delay=-1&repeatCount=1}}; wait until both fired, stop route B,
> then wait up to 3 s for 5 more exchanges from A: none arrive, A reports
> Started. 3 of 3 runs, and 10 of 10 in a loop; the same after B was started
> and stopped twice. Control: B {{timer:shared?delay=0&repeatCount=1}} (takes
> the timer): A keeps firing (3 of 3).
> A TLA+ model of the reference count with consumers that do and do not take
> the timer, started and stopped in any order, violates "every started consumer
> with a delay of 0 or more is scheduled on a Timer that is not cancelled" and
> "the count equals the consumers scheduled on the Timer" as soon as a
> negative-delay consumer is stopped; with the fix both hold (2 and 3
> consumers, up to 9 start/stop operations); with only non-negative delays they
> hold on the current code.
> h3. Proposed fix
> {{TimerConsumer}} remembers whether it took the timer (a flag set where
> {{getTimer}} is called in {{doStart}} and {{onCamelContextStarted}}) and
> {{doStop}} calls {{removeTimer}} only then, clearing the flag. It would also
> cover a consumer with a delay of 0 or more that is stopped before the
> CamelContext completed its start, which has not taken the timer yet either
> (not tested). With the fix route A keeps firing after B is stopped once or
> twice (3 of 3), the control is unchanged, and the timer tests of camel-core
> pass (19 classes, 34 tests, including {{TimerMultipleConsumerStopRouteTest}},
> {{TimerNegativeDelayTest}}, {{TimerRestartTest}} and a new stop/restart test
> of a negative-delay route next to a period route on the same timer name,
> which fails without the fix).
> Affected: all versions with delay=-1 (the same code at camel-3.20.0, 4.0.0,
> 4.10.0, 4.14.0, 4.18.0, 4.22.0 and main).
> Duplicate check (2026-09-30): JIRA text "TimerComponent" (12, the newest
> CAMEL-18232 thread name pattern), "timer" with "delay=-1" (CAMEL-9249),
> component camel-timer (none recent); GitHub pull requests "camel-timer",
> "timer removeTimer", "timer delay=-1": none about this.
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)