[
https://issues.apache.org/jira/browse/CAMEL-24584?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Claus Ibsen updated CAMEL-24584:
--------------------------------
Fix Version/s: 4.23.0
> camel-support: BackgroundTask.schedule keeps re-running a task that has
> completed or run out of budget
> ------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-24584
> URL: https://issues.apache.org/jira/browse/CAMEL-24584
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Affects Versions: 4.18.3, 4.20.0, 4.21.0, 4.22.0
> Reporter: Henrik
> Priority: Major
> Fix For: 4.23.0
>
>
> {{BackgroundTask.schedule(CamelContext, BooleanSupplier)}} submits the task
> with
> {{scheduleWithFixedDelay}} and returns the {{Future}}, but the task never
> cancels it. Once the task is finished, {{runTaskWrapper}} short-circuits on
> its own latch:
> {code:java}
> if (latch.getCount() == 0) {
> return;
> }
> {code}
> so the runnable keeps being re-run at the task interval, doing nothing, for
> the life of the executor. This happens on both terminal paths:
> * the supplier returned {{true}}, so the task is {{Completed}};
> * the budget ran out, so the task is {{Exhausted}}.
> Cancelling is left to every caller. {{camel-sjms}}
> ({{SimpleMessageListenerContainer}}) does cancel the future it keeps;
> {{camel-master}} did not, which is one of the observations in CAMEL-24583 -
> every leadership change left a repeating no-op task on the "Leadership" pool
> for the life of the route.
> The {{Exhausted}} case cannot be fixed by the caller at all. After the budget
> runs out the supplier is never invoked again, so nothing component-side is
> ever given the chance to notice and cancel.
> h2. Proposed fix
> Record the future inside {{schedule()}} and cancel it on the paths where the
> task can no longer do any work: {{Completed}}, {{Exhausted}}, and a guard for
> the case where a task with a zero initial delay finishes before the future
> has been published.
> The blocking {{run()}} path is deliberately left untouched: it already
> cancels the future it owns in {{waitForTaskCompletion}}, and {{camel-sjms}}
> branches on {{isRunning()}}, which that path controls.
> h2. Compatibility
> {{schedule()}} is public and is called from outside core. A caller that
> inspects the returned {{Future}} will now see {{isCancelled()}} return
> {{true}} once the task is done, where it previously stayed live forever.
> Callers that already cancel the future themselves are unaffected. An upgrade
> guide entry is included.
> h2. Not addressed here
> When a *caller* cancels the future instead, the task is never removed from
> the {{TaskManagerRegistry}} - {{runTaskWrapper}} only unregisters from inside
> a later run, which by then cannot happen. The task stays listed as {{Active}}
> in JMX and in the {{camel/internal-tasks}} dev console until the context
> stops. That affects {{camel-sjms}} today and {{camel-master}} after
> CAMEL-24583, and would be better fixed by giving {{BackgroundTask}} a cancel
> operation that also deregisters. Worth a separate issue.
> h2. References
> The behaviour dates back to CAMEL-22206, which introduced {{schedule()}} in
> 4.13.0. Related recent work in the same class: CAMEL-24278 and CAMEL-24286.
> The change is already included in the pull request for CAMEL-24583:
> https://github.com/apache/camel/pull/26028
--
This message was sent by Atlassian Jira
(v8.20.10#820010)