Hello Marcus,
I did some research on this and I think this belongs in camel-sjms as an
option on the existing consumer rather than as a new component, and it
should follow the shape camel-kafka already uses as per Claus and Otavio
CAMEL-20368 ("investigate adding batch support to other components"). I'd
not start with an SPI, but actually follow camel-kafka's batching consumer
implementation.
My proposal is to achieve a route like:
*from("sjms:queue:orders?batching=true&batchSize=500&batchTimeout=1000"
+ "&transacted=true&concurrentConsumers=4") .process(this::toRows)
// List<Exchange> -> List<Map<String,Object>> .to("sql:INSERT INTO
orders (id, payload) VALUES (:#id, :#payload)?batch=true");*
That would work like this: a new MessageListenerContainer (camel-sjms
already has that SPI, alongside SimpleMessageListenerContainer) creates a
transacted Session and a MessageConsumer once and holds both for the
consumer's lifetime. On its own thread it loops consumer.receive(...),
accumulating exchanges until batchSize or batchTimeout, then puts the
List<Exchange> into one batch exchange and calls the route synchronously
(to double check how and if this would work with virtual threads). The
commit happens from a Synchronization on that exchange, camel-sjms already
has TransactionOnCompletion, which commits or rolls back based on
exchange.isFailed() || isRollbackOnly(), and SjmsHelper.commitIfNeeded
already handles both session.commit() and CLIENT_ACKNOWLEDGE ->
message.acknowledge(). So most of the plumbing exists; the new part is the
receive loop.
On failure the session is rolled back and the broker redelivers all N with
JMSRedelivered=true. In this case, the user should be aware of it, and
eventually mitigate this behaviour with idempotency. Attached you can find
a sequence diagram that shows this.
Proposed options, following camel Kafka component:
- batching (boolean, default false), same as Kafka.
- batchSize (int), Kafka calls this maxPollRecords, but that's a verbatim
passthrough of the Kafka client property and means nothing in JMS.
- batchTimeout (duration), Kafka needs two knobs (pollTimeoutMs +
batchingIntervalMs) because Camel isn't in control during poll(); its docs
concede you can wait pollTimeoutMs + batchingIntervalMs. JMS doesn't have
that problem: receive(timeout) returns on a deadline you choose, so one
knob gives an exact bound.
- body = List<Exchange>, same as Kafka, so .split(body()) works the same
way.
- breakOnFirstError, not included. In Kafka's batching mode this commits
the failed batch so the consumer can move forward; in JMS that means
acknowledging a batch you failed to process, i.e. losing it. I'd rather
rely on broker redelivery + DLQ and add the single-message fallback later.
- allowManualCommit, not included.
Everything lands in camel-sjms, and camel-sjms2 inherits it for free since
Sjms2Endpoint extends SjmsEndpoint. With batching=false as the default, no
existing route changes behaviour.
- Does this cover your use case, or do you need the ack boundary finer than
the batch?
- The original request in CAMEL-16039 used
aggregationStrategy=#groupedBodyAggregationStrategy&completionSize=300. I'd
make List<Exchange> the default, but we could keep an optional
aggregationStrategy so routes written against the old sjms-batch port
unchanged, is it useful to you, or unnecessary?
- Would you like to implement it? In case a CAMEL Jira issue would be nice.
Once implemented, it would be great to know if and how it worked for your
use case.
Greetings,
Federico
Il giorno mer 16 set 2026 alle ore 15:53 Marcus Ionker <[email protected]>
ha scritto:
> Hello,
>
> In order to improve the performance of a JMS to Postgres route I need to
> batch process messages. In this case a at least once processing is
> sufficient. Ideally I could achieve the batch processing without using an
> additional persistence service. The SJMS component included a SJMS Batch
> component until version 3.7x. The Kafka and the NATS components offer a
> batch option, which obviously stems from how they work. There are also a
> few Jira tickets pertaining to a new batch solution for JMS and a few other
> components, but none have been started yet.
>
> - https://issues.apache.org/jira/browse/CAMEL-16039
> - https://issues.apache.org/jira/browse/CAMEL-16751
>
> Originally I thought about customizing the acknowledge behavior, commit
> the transaction after the batch has been processed and probably using a
> synchronous executor, but that does not appear possible with the SJMS (1 or
> 2) component, and would probably require a custom message lister container
> with the JMS component. I saw a few older forum entries suggesting avoiding
> doing so. Therefore I am now thinking about writing a custom component
> mimicking how the SJMS Batch worked. I will make it dependent on either
> version 1 or 2. I am happy to submit it to the project, therefore I wanted
> to reach out for comments. Should I mimic the SJMS Batch component or do
> something more similar to the batching in Kafka and NATS? If I should
> develop something similar to the SJMS Batch component and suggestions what
> to do differently?
>
> Thanks in advance.
>
> Marcus Ionker