Hi

I dont think pooled exchanges help very much - the majority of the data and
objects in the JVM are user data which cannot be reused, and as such the GC
needs to reclaim those.
And modern JVMs have fast GCs and you can tweak / configure them. But its a
skilled art to do that.

Vendors like Red Hat has a performance team that is specialized in that
that assist our customers with their needs.

There is that bug with pooled exchanges that throws this exception because
of your specialized situation with the recursion.
But pooled exchanges is seldom in use by Camel users - its a feature that
is not needed very much.

But it works for simpler use-cases and for serverless where you may use
Camel as a connector bridge and then with high streams coming in from Kafka
etc,
then this helps a bit to reduce the JVM - And you can if I recall also
preset a pool size so its "warmed up" that was something serverless desired
so a pod could spin up
and quickly handle the load without causing a JMV memory spike. That
overall helps to right size the JVM memory settings for the pods.



On Thu, Feb 26, 2026 at 2:03 AM Dark Knight <[email protected]>
wrote:

> Hi,
>
> Thanks for the clarification.
>
> In our case, the route calls itself to solve similar sub-problems during
> the enrichment process. Because the hierarchy depth and nested queries are
> dynamic, the self-calling route allows us to handle this generically.
> Without this pattern, it is difficult for us to process the data
> dynamically.
>
> Given this constraint, do you have any suggestions or recommended patterns
> to safely handle this scenario, especially when using pooled exchanges with
> parallel processing?
>
> Thanks for your guidance.
>
>
> On Tue, Feb 24, 2026 at 12:12 AM Claus Ibsen <[email protected]>
> wrote:
>
> > Hi
> >
> > Thanks for the details.
> >
> > If you don't call yourself but call another route that is similar then it
> > can continue.
> >
> >
> >
> > On Tue, Feb 24, 2026 at 4:54 AM Dark Knight <[email protected]>
> > wrote:
> >
> > > Thanks for the response!
> > >
> > > The sample I shared is just a reproducer. In the real scenario, we load
> > > millions of records from a database, transform them, and index them
> into
> > > SOLR. The SOLR document building stage runs with streaming and parallel
> > > processing enabled. We use the JDBC, SEDA, and SOLR components, along
> > with
> > > the Splitter and Aggregate EIPs, to accomplish this.
> > >
> > > We are currently seeing significant CPU usage during document building,
> > so
> > > we wanted to evaluate whether enabling exchange pooling would provide
> > > measurable performance or GC improvements. Since the splitter creates
> an
> > > exchange copy for each DB row, we thought enabling pooling could reduce
> > the
> > > load from object allocation. To give a rough estimate, we process about
> > 25M
> > > records.
> > >
> > > Regarding the recursive route, the SOLR document is a denormalized
> > > representation of data coming from normalized tables, and the
> processing
> > > involves nested queries and hierarchical enrichment steps. The
> > self-calling
> > > route is used to handle these nested processing stages in a generic and
> > > reusable way.
> > >
> > > On Mon, Feb 23, 2026 at 3:02 PM Claus Ibsen <[email protected]>
> > wrote:
> > >
> > > > Hi
> > > >
> > > > Ah sorry it is indeed the pooled exchanges and its more complex when
> > > > parallel and that you have recursive.
> > > > Turn off pooled and it works.
> > > >
> > > > What is the reason that you attempt to use pooled?
> > > >
> > > >
> > > >
> > > > On Mon, Feb 23, 2026 at 9:50 PM Claus Ibsen <[email protected]>
> > > wrote:
> > > >
> > > > > Hi
> > > > >
> > > > > No its not due to pooled, but due to parallel, so you have
> concurrent
> > > > > threads that trigger the splitter to prepare for splitting and then
> > > they
> > > > > may up in a thread safety issue.
> > > > > What you do is also weird and not common to recursive call the same
> > > > route.
> > > > >
> > > > >
> > > > >
> > > > > On Fri, Feb 20, 2026 at 8:13 PM Dark Knight <
> > > [email protected]>
> > > > > wrote:
> > > > >
> > > > >> Hi All,
> > > > >>
> > > > >> I’m observing an intermittent UnsupportedOperationException in
> > > Splitter
> > > > >> EIP
> > > > >> with parallel processing when the pooled exchange is enabled. The
> > > > scenario
> > > > >> is to flatten a nested list using a recursive route. The route has
> > > > >> streaming and parallel processing enabled.
> > > > >>
> > > > >>
> > > > >> The following exception is raised ~7 out of 10 runs
> > > > >>
> > > > >>
> > > > >> 11:32:17.179 [Camel (camel-1) thread #2 - Split] ERROR
> > > > >> org.apache.camel.processor.errorhandler.DefaultErrorHandler --
> > Failed
> > > > >> delivery for (MessageId: 6B26CA6266F8B1A-000000000000016E on
> > > ExchangeId:
> > > > >> 6B26CA6266F8B1A-000000000000016E). Exhausted after delivery
> > attempt: 1
> > > > >> caught: java.lang.UnsupportedOperationException: Is this really
> > > correct
> > > > ?
> > > > >>
> > > > >> Message History (source location and message history is disabled)
> > > > >>
> > > > >>
> > > >
> > >
> >
> ---------------------------------------------------------------------------------------------------------------------------------------
> > > > >> Source                                   ID
> > > > >> Processor                                          Elapsed (ms)
> > > > >>                                         route1/route1
> > > > >> from[direct://processList]                                    8
> > > > >> ...
> > > > >>                                         route1/split1
> > > > >> split[simple{${body}}]                                        0
> > > > >>
> > > > >> Stacktrace
> > > > >>
> > > > >>
> > > >
> > >
> >
> ---------------------------------------------------------------------------------------------------------------------------------------
> > > > >> java.lang.UnsupportedOperationException: Is this really correct ?
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.MulticastProcessor.wrapInErrorHandler(MulticastProcessor.java:1063)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.MulticastProcessor.createProcessorExchangePair(MulticastProcessor.java:1045)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.Splitter$SplitterIterable$1.next(Splitter.java:243)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.Splitter$SplitterIterable$1.next(Splitter.java:184)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.MulticastProcessor$MulticastReactiveTask.getNextProcessorExchangePair(MulticastProcessor.java:640)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.MulticastProcessor$MulticastReactiveTask.run(MulticastProcessor.java:557)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.doRun(DefaultReactiveExecutor.java:199)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.executeReactiveWork(DefaultReactiveExecutor.java:189)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.tryExecuteReactiveWork(DefaultReactiveExecutor.java:166)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:148)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleSync(DefaultReactiveExecutor.java:64)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> org.apache.camel.processor.MulticastProcessor.lambda$doProcess$0(MulticastProcessor.java:362)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
> > > > >> at
> > java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
> > > > >> at
> > > > >>
> > > > >>
> > > >
> > >
> >
> java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
> > > > >> at java.base/java.lang.Thread.run(Thread.java:833)
> > > > >>
> > > > >>
> > > > >> Test Code
> > > > >>
> > > > >>
> > > > >> public class FlattenListTest extends CamelTestSupport {
> > > > >>
> > > > >>    private static final int L1 = 20;
> > > > >>
> > > > >>    private static final int L2 = 5;
> > > > >>
> > > > >>    private static final int L3 = 5;
> > > > >>
> > > > >>    @Override
> > > > >>
> > > > >>    protected RoutesBuilder createRouteBuilder() {
> > > > >>
> > > > >>        return new RouteBuilder() {
> > > > >>
> > > > >>            @Override
> > > > >>
> > > > >>            public void configure() {
> > > > >>
> > > > >>            from("direct:processList")
> > > > >>
> > > > >>                .choice()
> > > > >>
> > > > >>                    .when(exchange -> (exchange.getIn().getBody()
> > > > >> instanceof
> > > > >> List))
> > > > >>
> > > > >>
> > > > .split(body()).streaming().parallelProcessing(true)
> > > > >>
> > > > >>                        .to("direct:processList")
> > > > >>
> > > > >>                    .endChoice()
> > > > >>
> > > > >>                    .otherwise()
> > > > >>
> > > > >>                        .log("${body}")
> > > > >>
> > > > >>                        .to("mock:result")
> > > > >>
> > > > >>                    .end();
> > > > >>
> > > > >>            }
> > > > >>
> > > > >>        };
> > > > >>
> > > > >>    }
> > > > >>
> > > > >>    @Override
> > > > >>
> > > > >>    protected CamelContext createCamelContext() throws Exception {
> > > > >>
> > > > >>        CamelContext camelContext = super.createCamelContext();
> > > > >>
> > > > >>        ExtendedCamelContext ecc =
> > > > camelContext.getCamelContextExtension();
> > > > >>
> > > > >>        ecc.setExchangeFactory(new PooledExchangeFactory());
> > > > >>
> > > > >>        ecc.setProcessorExchangeFactory(new
> > > > >> PooledProcessorExchangeFactory());
> > > > >>
> > > > >>        ecc.getExchangeFactory().setStatisticsEnabled(true);
> > > > >>
> > > > >>
> ecc.getProcessorExchangeFactory().setStatisticsEnabled(true);
> > > > >>
> > > > >>        return camelContext;
> > > > >>
> > > > >>    }
> > > > >>
> > > > >>    @Test
> > > > >>
> > > > >>    public void testSplitter() throws Exception {
> > > > >>
> > > > >>        List<List<List<Integer>>> data = new ArrayList<>();
> > > > >>
> > > > >>        int num = 0;
> > > > >>
> > > > >>        for (int i = 0; i < L1; i++) {  // Outer level
> > > > >>
> > > > >>            List<List<Integer>> level2 = new ArrayList<>();
> > > > >>
> > > > >>            for (int j = 0; j < L2; j++) {  // Middle level
> > > > >>
> > > > >>                List<Integer> level3 = new ArrayList<>();
> > > > >>
> > > > >>                for (int k = 0; k < L3; k++) {  // Inner level
> > > > >>
> > > > >>                    level3.add(num++);
> > > > >>
> > > > >>                }
> > > > >>
> > > > >>                level2.add(level3);
> > > > >>
> > > > >>            }
> > > > >>
> > > > >>            data.add(level2);
> > > > >>
> > > > >>        }
> > > > >>
> > > > >>        getMockEndpoint("mock:result").expectedMessageCount(num);
> > > > >>
> > > > >>        template.sendBody("direct:processList", data);
> > > > >>
> > > > >>        MockEndpoint.assertIsSatisfied(context);
> > > > >>
> > > > >>    }
> > > > >>
> > > > >> }
> > > > >>
> > > > >>
> > > > >> The route should flatten the nested list and deliver all
> individual
> > > > >> elements to the final endpoint without exceptions or data loss.
> > Please
> > > > let
> > > > >> me know if this is a known limitation or if I’m misusing pooled
> > > > exchanges
> > > > >> in this scenario.
> > > > >>
> > > > >>
> > > > >> Camel Version: 4.18.0
> > > > >>
> > > > >> Java Version: 17
> > > > >>
> > > > >
> > > > >
> > > > > --
> > > > > Claus Ibsen
> > > > >
> > > >
> > > >
> > > > --
> > > > Claus Ibsen
> > > >
> > >
> >
> >
> > --
> > Claus Ibsen
> >
>


-- 
Claus Ibsen

Reply via email to