[ 
https://issues.apache.org/jira/browse/CAMEL-25100?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18120166#comment-18120166
 ] 

shashank commented on CAMEL-25100:
----------------------------------

PR: https://github.com/apache/camel/pull/27002 (builds on CAMEL-25012, which is 
now merged).

I cannot assign issues to myself; could a committer assign this to me 
(smjainblr)? Thanks.

_Claude Code on behalf of allthingssecurity_

> camel-core - OnCompletion EIP (default after-consumer mode) cannot read a 
> body spooled to disk by stream caching, as the spool file is deleted before 
> the onCompletion runs
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25100
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25100
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core
>            Reporter: shashank
>            Priority: Minor
>
> With stream caching spooled to disk ({{spoolEnabled=true}}, a body over the 
> spool threshold), the body is a {{FileInputStreamCache}}. Its temporary file 
> is deleted by an on completion that 
> {{FileInputStreamCache.TempFileManager.addExchange}} registers on the 
> exchange ({{FileInputStreamCache.java:255}}). That on completion is a 
> {{SynchronizationAdapter}} with the default order 0 
> ({{SynchronizationAdapter.java:49}}).
> An {{onCompletion()}} in the default mode ({{modeAfterConsumer}}) also runs 
> as an on completion of the unit of work 
> ({{OnCompletionSynchronizationAfterConsumer}}), with the order 
> {{Ordered.LOWEST}} ({{OnCompletionProcessor.java:326}}). {{UnitOfWorkHelper}} 
> sorts the on completions by their order ({{UnitOfWorkHelper.java:112}}), so 
> the spool file is always deleted before the onCompletion starts. The 
> onCompletion then works on a copy of the exchange ({{prepareExchange}}, 
> {{OnCompletionProcessor.java:280}}) whose body is the 
> {{FileInputStreamCache}} of the deleted file.
> Results with a small spool threshold and a streamed body of 16 KB (and, in 
> the original investigation, 100 KB with a 1 KB threshold, 3 runs each):
> * {{onCompletion().convertBodyTo(byte[].class)}}: fails with a 
> {{NoSuchFileException}} for the spool file, every time.
> * {{onCompletion().onFailureOnly()}} on a route that fails: the same.
> * {{onCompletion().parallelProcessing()}}: the onCompletion route stops at 
> the first step that reads the body, and nothing is logged at WARN or above.
> * {{onCompletion().modeBeforeConsumer()}}: works, as it runs before the unit 
> of work is done.
> * Without an onCompletion, and for bodies below the threshold (kept in 
> memory), there is no problem.
> Typical onCompletion uses (archive or audit the message, send a notification 
> with the payload) therefore fail as soon as the payload is big enough to be 
> spooled.
> h3. Proposed fix
> * The stream cache clean-up on completion returns {{Ordered.LOWEST}} from 
> {{getOrder()}}, so it runs after the other on completions of the exchange, 
> which may still read the body.
> * The after-consumer onCompletion uses {{Ordered.LOWEST - 1}}, so it still 
> runs before the on completions that want to be last (such as the FTP and SMB 
> consumers' disconnect), and {{prepareExchange}} gives its copy its own 
> reference to the stream cache: it removes {{CamelStreamCacheUnitOfWork}} from 
> the copy and replaces the body with {{sc.copy(copy)}}, as the Wire Tap EIP 
> does ({{WireTapProcessor.java:282}}). The copy keeps the file until the 
> onCompletion route is done, which also covers {{parallelProcessing}}.
> * With {{parallelProcessing}}, a task that never runs must release the copy's 
> reference: when the thread pool rejects the task, discards it because it is 
> shut down, or drops it when the processor shuts the pool down with 
> {{shutdownNow}}. Otherwise the file would be kept until the spool directory 
> is removed when the context stops. Since CAMEL-25012 the processor also 
> counts its parallel tasks as pending for the graceful shutdown, so a task 
> that never runs must also stop being counted. That already happened for a 
> rejected task and for the tasks dropped by {{shutdownNow}}, but not for a 
> task that a thread pool that is shut down discards without an exception (such 
> as with the {{CallerRuns}} policy): it stayed counted as pending. Both are 
> now done in one place: each parallel task is either run or discarded, never 
> both, and a discarded task is no longer counted as pending and releases its 
> copy.
> The first point changes the order of every stream cache clean-up, not only 
> for routes with an onCompletion: a spooled file is now deleted after the 
> other on completions of the exchange instead of among the order 0 ones. The 
> file is only deleted later than before, never earlier, so nothing that worked 
> before can now see a deleted file. On completions that share the order 
> {{Ordered.LOWEST}} keep their reverse registration order among themselves. 
> This needs an upgrade guide note.
> With this change the onCompletion variants above read the full body, and no 
> spool file is left behind afterwards, also when a parallel task is rejected, 
> discarded, or dropped at shutdown.
> Affected: long-standing, all 4.x versions (the order of the two on 
> completions has not changed).
> Duplicate check (2026-09-28): JIRA "onCompletion" with "stream cache", 
> "stream caching", "spool" or "FileInputStreamCache": CAMEL-2776 (2010, 
> deletion on close), CAMEL-2636 and unrelated issues. CAMEL-25012 (fixed) is 
> about the graceful shutdown of the parallel onCompletion, not this, but this 
> change builds on it. GitHub pull requests: nothing on this.
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to