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

Work on CAMEL-25724 started by shashank.
----------------------------------------
> camel-jms - with preserveMessageQos=true a message without JMSExpiration is 
> sent with no time to live, ignoring the endpoint timeToLive and, for 
> request/reply, the requestTimeout, so stale messages never expire
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25724
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25724
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-jms
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> The {{preserveMessageQos}} option is documented as: "The following three 
> headers are considered JMSPriority, JMSDeliveryMode, and JMSExpiration. You 
> can provide all or only some of them. If not provided, Camel will fall back 
> to use the values from the endpoint instead."
> {{JmsConfiguration.CamelJmsTemplate.doSend}} (main e339a2e9019f) does that 
> for the priority, but not for the time to live:
> {code:java}
> if (config.isPreserveMessageQos()) {
>     long ttl = message.getJMSExpiration();
>     if (ttl != 0) {
>         ttl = ttl - System.currentTimeMillis();
>         if (ttl <= 0) {
>             ttl = 1;
>         }
>     }
>     int priority = message.getJMSPriority();
>     if (priority < 0 || priority > 9) {
>         // use priority from endpoint if not provided on a message with a 
> valid range
>         priority = this.getPriority();
>     }
>     ...
>     producer.send(message, deliveryMode, priority, ttl);
> {code}
> A message without a {{JMSExpiration}} header has expiration 0, so it is sent 
> with time to live 0, which in JMS means "never expires". The time to live of 
> the template is never used on this path:
> * InOnly: {{to("jms:queue:orders?preserveMessageQos=true&timeToLive=60000")}} 
> sends messages that never expire.
> * InOut: {{createInOutTemplate}} sets the {{requestTimeout}} (default 20 s) 
> as time to live of the template ("About time to live" in the component page), 
> but with {{preserveMessageQos=true}} the requests are sent without it. A 
> request whose caller already timed out stays on the queue and is processed 
> later, and requests pile up when the server is down.
> There is no error and no log. Messages that come from another JMS endpoint 
> usually carry their own {{JMSExpiration}}; the defect hits messages created 
> by Camel (from a file, HTTP, timer, ...) and the typical reason to use the 
> option, setting only a {{JMSPriority}} header.
> Trigger: {{preserveMessageQos=true}} and a message without {{JMSExpiration}} 
> (or 0), with {{timeToLive}} set (InOnly) or with request/reply (any 
> {{requestTimeout}} > 0, the default) and {{disableTimeToLive=false}} (the 
> default).
> h3. Reproduction
> New test {{JmsPreserveMessageQosTimeToLiveTest}} (6 tests, embedded Artemis 
> and a mocked {{MessageProducer}}). Three fail on main:
> * {{jms:queue:qos?preserveMessageQos=true&timeToLive=5000}}, message without 
> expiration: {{MessageProducer.send}} gets time to live 0, expected 5000;
> * InOut template of {{jms:queue:qos?preserveMessageQos=true}} (default 
> requestTimeout 20000): time to live 0, expected 20000;
> * a route 
> {{from("direct:start").to("activemq:queue:X?preserveMessageQos=true&timeToLive=600000")}}
>  on the embedded broker: the received message has {{JMSExpiration}} 0, 
> expected about now + 10 minutes.
> Three more pass on main and guard the parts that must not change: a message 
> with an expiration keeps its remaining time; {{disableTimeToLive=true}} sends 
> 0; an endpoint without timeToLive sends 0.
> A Z3 model of the chain (template time to live, header, {{exp - now}} with 
> the {{<= 0}} clamp, 64-bit) gives the counterexamples above and shows that 
> the fix meets the documented fallback for every input in realistic ranges, 
> and changes nothing when the message has an expiration or the InOnly endpoint 
> has no time to live.
> h3. Proposed fix
> When the message has no expiration, use the time to live of the template 
> ({{this.getTimeToLive()}}), which is the endpoint {{timeToLive}} (InOnly), 
> {{timeToLive}}/{{requestTimeout}} (InOut), and 0 when none is configured or 
> {{disableTimeToLive=true}}. Four lines in {{doSend}}; the camel-jms tests 
> pass with it (452 + 16 + 6 run in the three surefire executions, 0 failures, 
> 0 errors, 11 skipped). Note for the 4.24 upgrade guide: such messages now 
> expire; {{disableTimeToLive=true}} keeps the old behaviour. A message bridged 
> from another JMS endpoint with expiration 0 also gets the endpoint value, 
> because the producer cannot tell a 0 header from a missing one (the priority 
> has the same limit).
> Same code, not changed here: camel-sjms {{SjmsTemplate.send}} (the 
> {{preserveMessageQos}} branch ignores the endpoint {{timeToLive}} the same 
> way).
> Affected: main (tested); camel-4.23.x, camel-4.22.x, camel-4.18.x and 
> camel-4.14.x have the same lines (read, not run).
> Duplicate check (2026-10-17): JIRA text "preserveMessageQos timeToLive", 
> "preserveMessageQos JMSExpiration", "requestTimeout header time to live", 
> summaries with "time to live": CAMEL-3743, CAMEL-4124, CAMEL-17912 (delivery 
> mode and priority), CAMEL-7026 (request timeout header), none about this. 
> GitHub pull requests "preserveMessageQos", "camel-jms timeToLive": none about 
> this.
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to