[
https://issues.apache.org/jira/browse/CAMEL-24091?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Federico Mariani updated CAMEL-24091:
-------------------------------------
Attachment:
FileConsumerIdempotentRollbackChangedFileNameHeaderIssueTest.java
> camel-file: completion-time idempotentKey evaluated against route-mutated
> headers - failed files never retried (eager) or endless duplicates
> (non-eager); regression of CAMEL-21733
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-24091
> URL: https://issues.apache.org/jira/browse/CAMEL-24091
> Project: Camel
> Issue Type: Bug
> Components: camel-file, camel-ftp
> Affects Versions: 4.21.0
> Reporter: Federico Mariani
> Priority: Major
> Labels: code-review
> Attachments:
> FileConsumerIdempotentRollbackChangedFileNameHeaderIssueTest.java
>
>
> h3. Problem
> When {{idempotentKey}} is an expression (the documented
> {{${file:name}-${file:size}}} style), the poll-time key is evaluated on a
> pristine file exchange ({{dynamic == null}} for scheduled polls). At
> completion, {{GenericFileOnCompletion.processStrategyCommit/Rollback}}
> (GenericFileOnCompletion.java:119, 162) re-evaluates the key via
> {{GenericFileHelper.createDummy(endpoint, exchange, ...)}} - and
> {{createDummy}} copies *all headers of the routed exchange over the dummy
> with override=true* ({{MessageHelper.copyHeaders(..., true)}}). Any route
> that mutates {{CamelFileName}}/{{CamelFileLength}} - the classic
> {{setHeader(Exchange.FILE_NAME, ...)}} before a file/ftp producer - makes the
> completion-time key differ from the poll-time key.
> h3. Failure scenarios
> * {{idempotentEager=true}} (default): rollback calls {{remove(wrongKey)}} ->
> the eagerly-added real key stays -> a *failed file is never retried* (silent
> loss).
> * {{idempotentEager=false}}: commit calls {{add(wrongKey)}} -> real key never
> added -> with {{noop=true}} the file is *re-consumed on every poll* (endless
> duplicates).
> * Eager + repos where {{confirm()}} is meaningful (JDBC/Kafka-style
> pending-confirm repos): {{confirm(wrongKey)}} leaves the real entry
> unconfirmed -> re-consumed after restart.
> h3. Related variant (pre-existing)
> With {{recursive=true}} + {{preMove}}, the OnCompletion holds the
> *post-preMove* file ({{GenericFileConsumer.java:470}}), and
> {{GenericFile.changeFileName}} keeps only the last path segment - so
> {{${file:name}}}-based keys differ from poll time even without header
> mutation, with the same failure modes.
> h3. History
> Before CAMEL-21733 (f27c9b212768, Camel 4.11) the completion dummy was
> {{endpoint.createExchange(file)}} - pure file headers. The enrichment was
> added so *dynamic poll* caller headers stay resolvable, but on the completion
> path the "dynamic" argument is the fully-routed exchange, overriding the very
> {{CamelFile*}} headers the key is computed from.
> h3. Suggested fix
> Snapshot the poll-time key on the exchange (property) and reuse it at
> commit/rollback - this fixes both the header-mutation regression and the
> preMove/recursive variant in one place. Alternatively, exclude {{CamelFile*}}
> headers from the completion-path enrichment.
> h3. Reproducer
> Attached failing JUnit test (place in
> {{core/camel-core/src/test/java/org/apache/camel/component/file/}}, where the
> file component tests live). Route sets {{CamelFileName}} then fails on first
> attempt; with the bug the rollback removes the wrong key and the file is
> never retried.
> ----
> _This issue was researched and filed by Claude Code on behalf of [~croway]
> (GitHub: Croway), as part of a deep code review of camel-file and camel-ftp.
> A failing JUnit reproducer is attached; it fails deterministically on current
> main (4.22.0-SNAPSHOT)._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)