[ 
https://issues.apache.org/jira/browse/CAMEL-24141?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen reassigned CAMEL-24141:
-----------------------------------

    Assignee: Claus Ibsen

> camel-core - Aggregate EIP recovery and completionInterval background tasks 
> are permanently cancelled by the first exception
> ----------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24141
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24141
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core, eip
>    Affects Versions: 4.21.0
>            Reporter: Federico Mariani
>            Assignee: Claus Ibsen
>            Priority: Major
>         Attachments: AggregateIntervalTaskDiesOnExceptionIssueTest.java, 
> AggregateRecoverTaskDiesOnExceptionIssueTest.java
>
>
> Two of the Aggregate EIP's periodic background tasks are scheduled directly 
> on a {{ScheduledExecutorService}} without any exception guard. Per 
> {{scheduleWithFixedDelay}}/{{scheduleAtFixedRate}} semantics, the first 
> exception that escapes {{run()}} *permanently cancels all subsequent 
> executions*:
> # *RecoverTask* ({{AggregateProcessor.java:1449-1557}}, scheduled at :1635): 
> {{recoverable.scan(camelContext)}}, {{recover(...)}}, {{confirm(...)}} and 
> {{onSubmitCompletion(...)}} are all outside any try/catch (only the 
> dead-letter {{send}} is wrapped). A single transient failure — e.g. a 
> momentary DB outage while {{JdbcAggregationRepository.scan()}} runs — 
> permanently disables recovery until the route is restarted, with nothing but 
> a one-off stack trace in the logs. For persistent aggregation this means 
> completed-but-unconfirmed exchanges are never redelivered: effective data 
> loss.
> # *AggregationIntervalTask* ({{AggregateProcessor.java:1384-1437}}, scheduled 
> at :1666): {{aggregationRepository.getKeys()}} is called outside any 
> try/catch, and inside the loop only {{OptimisticLockingException}} is caught. 
> Any other repository/strategy exception kills the fixed-rate task forever — 
> the aggregator keeps accepting and aggregating messages but *never completes 
> any group by completionInterval*: unbounded memory growth with a memory 
> repository, indefinitely stuck groups with a persistent one.
> The project already knows this failure mode: 
> {{DefaultTimeoutMap.purgeTask()}} ({{DefaultTimeoutMap.java:163-176}}) 
> catches all exceptions with the comment _"must catch and log exception 
> otherwise the executor will not schedule next purgeTask"_ — which is why the 
> completionTimeout checker survives repository hiccups but recovery and 
> interval completion do not.
> Related robustness issue on the same path: {{aggregateCompletionCounter}} 
> ({{AggregateProcessor.java:924-952}}) does {{switch (completedBy)}} which 
> NPEs when the {{CamelAggregatedCompletedBy}} property is absent (e.g. a 
> recovered exchange from a repository that did not persist that property) — on 
> the recovery path that NPE is itself a task-killer via the missing guard 
> above. A null-safe default branch would fix it.
> *Reproducers (attached, both fail on main):*
> * {{AggregateRecoverTaskDiesOnExceptionIssueTest}} — recoverable repository 
> whose {{scan()}} throws once; the pending unconfirmed exchange is never 
> recovered afterwards.
> * {{AggregateIntervalTaskDiesOnExceptionIssueTest}} — repository whose 
> {{getKeys()}} throws once; a group aggregated afterwards is never completed 
> by interval.
> Suggested fix: wrap the body of both tasks in try/catch that routes to the 
> aggregator's {{ExceptionHandler}} (same pattern as 
> {{DefaultTimeoutMap.purgeTask}}), and make {{aggregateCompletionCounter}} 
> null-safe.
> _Filed by Claude Code on behalf of Federico Mariani (fmariani)_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to