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

shashank reassigned CAMEL-25522:
--------------------------------

    Assignee: shashank

> camel-ibm-cos - consumer with fileName routes the object again while its 
> exchange is in flight, and a batch cut short by a route stop leaves its 
> objects in progress and their streams open
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25522
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25522
>             Project: Camel
>          Issue Type: Bug
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> The consumer adds each listed key to the endpoint's {{inProgressRepository}} 
> ({{IBMCOSConsumer.createExchanges}}, line 163 at main 5af71ab258b8) and 
> removes it in the on completion that {{createExchange}} adds (lines 230-240), 
> which also closes the object's content stream ({{includeBody=true}} and 
> {{autocloseBody=true}}, the defaults, lines 190 and 216-222). Two paths miss 
> it:
> * With {{fileName}} set, {{poll}} gets the object on every poll (lines 68-72) 
> without looking at the repository. With an asynchronous route, for example 
> {{to("seda:...")}} (seda hands the on completion over to its consumer), an 
> asynchronous producer or {{threads()}}, {{processBatch}} returns before the 
> exchange is done and the next poll (500 ms later by default) gets the object 
> again and routes it a second time ({{deleteAfterRead=true}}, the default, 
> deletes it only when the first exchange completes).
> * When the consumer stops while it processes a batch, {{isBatchAllowed()}} 
> turns false and {{processBatch}} drops the remaining exchanges (line 124; 
> their objects stay in the bucket, by design with the default 
> {{ShutdownRunningTask.CompleteCurrentTaskOnly}}). Their on completions never 
> run: their keys stay in the repository (a memory repository of 10000 entries, 
> only cleared when the endpoint stops), so after a route stop and start the 
> next polls skip these objects as "already in progress" and they are never 
> consumed until the CamelContext is restarted; and their content streams, 
> opened by {{getObject}} for every listed object before the batch is routed, 
> are never closed, so each such stop keeps up to {{maxMessagesPerPoll}} - 1 
> connections of the client's pool (50 by default).
> h3. Reproduction
> New {{IBMCOSConsumerInProgressTest}}, with a small in-process fake of the S3 
> calls the consumer makes (JDK {{HttpServer}}, path-style) and an IBM COS 
> client with static HMAC credentials pointing at it ({{cosClient=#cos}}):
> * {{objectInFlightIsNotConsumedAgainWithFileName}}: {{fileName=a.txt}}, route 
> to {{seda:hold}}, the seda route holds the exchange until the consumer has 
> completed a second poll (counted with a {{pollStrategy}}). On main: {{a.txt 
> was consumed again by a later poll while its first exchange was still in 
> flight ==> expected: <1> but was: <2>}}.
> * {{objectsOfAStoppedBatchAreConsumedAfterRestart}}: three objects, the first 
> exchange stops the route (from another thread) and waits until the consumer 
> no longer processes the batch; after the route is stopped and started again, 
> {{b.txt}} and {{c.txt}} must be consumed. On main: {{mock://result Received 
> message count. Expected: <2> but was: <0>}}.
> * {{notProcessedExchangesCloseTheirContent}}: {{processBatch}} of a consumer 
> that is not started (so it processes nothing) must release the key and close 
> the body stream of the exchange. On main: {{b.txt is still in progress ==> 
> expected: <false> but was: <true>}}; with the key fix but without the close 
> (mutation): the close assertion fails.
> h3. Proposed fix
> With {{fileName}}, the key is added to the in-progress repository before the 
> get (when a repository is configured, as in the listing); the poll is skipped 
> while it is already there, and the key is removed when the get fails (and, as 
> before, when the exchange is done). After the batch loop, the keys of the 
> exchanges a stopping consumer did not process are removed and their body 
> streams closed. No new option. 4.23 upgrade-guide note. camel-ibm-cos unit 
> tests: 5, 0 failures (the ITs need an IBM Cloud account and were not run).
> Found with TLA+ models of the consumer (the same models as the camel-aws2-s3 
> ticket, whose consumer has the same steps): with {{fileName}} and an 
> asynchronous route, "with deleteAfterRead every object is routed once" is 
> violated in 5 steps; for the listing, "every object is routed by one of the 
> polls" is violated in 12 steps (a stop drops the batch, then every later poll 
> skips its objects). Both hold with the fix. The open streams are not 
> modelled; they were found by reading the code next to the model and are 
> covered by the third test.
> Affected: main, camel-4.22.x, camel-4.18.x (the component is not in 4.14.x).
> Duplicate check (2026-10-10): JIRA text "ibm-cos" (10 issues; CAMEL-24491 
> fixed the listing's in-progress check, the others are producer and header 
> fixes), "inProgressRepository" (9, none about ibm-cos); GitHub pull requests: 
> no open PR touches {{IBMCOSConsumer}}.
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to