[
https://issues.apache.org/jira/browse/CAMEL-26634?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-26634 started by shashank.
----------------------------------------
> camel-core - Resequence EIP: batch mode can run two senders after a route
> restart
> ---------------------------------------------------------------------------------
>
> Key: CAMEL-26634
> URL: https://issues.apache.org/jira/browse/CAMEL-26634
> Project: Camel
> Issue Type: Bug
> Components: camel-core
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> Found with Fray (controlled concurrency testing for the JVM): a test that
> sends to a batch resequencer while its route is stopped and started logged
> {{java.util.ConcurrentModificationException}} at
> {{Resequencer$BatchSender.sendExchanges}} (the {{TreeSet}} iterator) in 2 of
> 60 schedules.
> Since CAMEL-20435 every start creates a new {{BatchSender}} thread, and
> {{doStop}} only interrupts the old one ({{cancel()}} = {{interrupt()}}). The
> stop does not wait for the exchange the old sender is delivering (the
> resequencer completes the incoming exchanges when it queues them, so the
> route has nothing inflight). If the route is started again before the old
> sender finishes that exchange, the old sender goes on: {{while
> (isRunAllowed())}} is true again, so it continues with its batch and its next
> rounds (it only ends at the interruptible {{await}}, and only while its
> interrupt status is still set). Both senders then iterate and remove from the
> same {{collection}} (a {{TreeSet}}, shared by all senders):
> - the new sender delivers the rest of the old batch while the old sender is
> still delivering an earlier exchange, so the exchanges are no longer
> delivered one at a time in order (a test sees 2, 3, 4 delivered before 1 is
> done);
> - the old sender's iterator then fails with
> {{ConcurrentModificationException}};
> - when the downstream processing clears the interrupt status (some libraries
> swallow it), the old sender never ends: two senders run on the same
> collection until the route is stopped again, and every such restart can add
> one more.
> Reproducer (plain JUnit, latches, no sleep):
> {{batch().size(2).timeout(60000)}}; the processor of message 1 waits;
> meanwhile 2 waits in the collection; stop and start the route; send 3 and 4.
> On main the mock gets 2, 3, 4 before 1; with a processor that clears the
> interrupt status, two "Batch Sender" threads stay alive.
> Ways to get there: any stop + start of the route (JMX, dev console, control
> bus, CLI, route policies) while the resequencer delivers a slow exchange.
> Expected: one sender at a time, so the exchanges are sent in order also
> across a restart, and the old sender ends.
> Suggested fix: a {{cancelled}} flag next to the interrupt (checked by the
> sender loop), and the sender of a new start waits for the previous sender to
> end before it sends anything (the start itself does not wait).
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)