Hello, Here is a sample project for reproducing the issue: https://github.com/VeijoFromTrimble/camel-http-resend-issue
-- Veijo Länsikunnas -- Veijo Länsikunnas | He/Him Senior Integration Architect, Forestry ________________________________ Hatsinanpuisto 8, 02600 Espoo Finland +358 40 545 7525 Mobile [email protected] forestry.trimble.com This email may contain confidential information that is intended only for the listed recipient(s) of this email. Any unauthorized review, use, disclosure or distribution is prohibited. If you believe you have received this email in error, please immediately delete this email and any attachments, and inform me via reply email. ma 29.9.2025 klo 13.58 Claus Ibsen ([email protected]) kirjoitti: > > Hi > > Can you put together a reproducer sample project that you can either attach > as a .zip to a JIRA ticket or put on github for others to take a look at. > > > On Fri, Sep 26, 2025 at 12:03 PM Veijo Länsikunnas > <[email protected]> wrote: > > > Hello, > > > > I just noticed an issue in our app, that http redelivery was sending > > extra messages to the target url. I first thought it to be related to > > jms transactions, but with a closer look this happens with just a > > simple retry. > > > > Here is a simple test case to view the result. The message should be > > sent twice (original and retry), but it gets sent four times. > > > > import org.apache.camel.Exchange; > > import org.apache.camel.LoggingLevel; > > import org.apache.camel.builder.RouteBuilder; > > import org.springframework.stereotype.Component; > > > > @Component > > public class TestRoute extends RouteBuilder { > > private static final String DIRECT_EXHAUSTED = "direct:exhausted"; > > private static final long DEFAULT_RESPONSE_CODE = 503; > > public static final String SINK = "http://localhost:29999/sink"; > > > > @Override > > public void configure() { > > > > > > > > errorHandler(deadLetterChannel(DIRECT_EXHAUSTED).maximumRedeliveries(1).redeliveryDelay(10000).logExhausted(false)); > > from("timer:camel-timer?repeatCount=1") > > .setBody(constant("Hello world!")) > > .log(LoggingLevel.INFO, "This is request ") > > .to(SINK); > > > > from(DIRECT_EXHAUSTED) > > .routeId("exhausted") > > .log(LoggingLevel.INFO, "Retries exhausted ${exception}"); > > > > from("jetty:"+SINK) > > .log("Request headers: ${headers}") > > .setHeader(Exchange.HTTP_RESPONSE_CODE, > > constant(DEFAULT_RESPONSE_CODE)) > > .log("Finished"); > > } > > } > > > > > > When I set http activity logging to be used, it sent the message only > > twice and failed with a null pointer exception in the logger. I > > created a simpler logger to just log the invocations without anything > > that could fail when values are null > > > > import org.apache.camel.Exchange; > > import org.apache.camel.component.http.HttpActivityListener; > > import org.apache.hc.core5.http.HttpEntity; > > import org.apache.hc.core5.http.HttpHost; > > import org.apache.hc.core5.http.HttpResponse; > > import org.slf4j.Logger; > > import org.slf4j.LoggerFactory; > > import org.springframework.stereotype.Component; > > import org.apache.hc.core5.http.HttpRequest; > > > > @Component > > public class HttpActivityLogger implements HttpActivityListener { > > > > private static final Logger LOGGER = > > LoggerFactory.getLogger(HttpActivityLogger.class); > > > > @Override > > public void onRequestSubmitted(Object source, Exchange exchange, > > HttpHost host, HttpRequest request, HttpEntity entity) { > > LOGGER.info("{} onRequestSubmitted: {}", exchange, source); > > LOGGER.trace("{} Stack trace: {}", exchange, > > Thread.currentThread().getStackTrace()); > > } > > > > @Override > > public void onResponseReceived(Object source, Exchange exchange, > > HttpHost host, HttpResponse response, HttpEntity entity, long elapsed) > > { > > LOGGER.info("{} Spent {} milliseconds", exchange, elapsed); > > } > > } > > > > > > Here is the log from the execution where the extra call with null > > exchange occurs a few milliseconds later that the original > > > > 2025-09-25T10:32:22.403+03:00 Apache Camel 4.10.6 (camel-1) started in > > 362ms (build:0ms init:0ms start:362ms boot:985ms) > > 2025-09-25T10:32:22.405+03:00 Started CamelTestApplication in 2.671 > > seconds (process running for 3.157) > > 2025-09-25T10:32:23.416+03:00 This is request > > 2025-09-25T10:32:23.455+03:00 > > Exchange[DDE7F0CB4616F92-0000000000000000] onRequestSubmitted: > > org.apache.camel.component.http.HttpEndpoint$1@427b9a63 > > 2025-09-25T10:32:23.548+03:00 Request headers: {Accept-Encoding=gzip, > > x-gzip, deflate, CamelHttpMethod=POST, CamelHttpPath=, > > CamelHttpQuery=null, CamelHttpUri=/sink, > > CamelHttpUrl=http://localhost:29999/sink, > > CamelServletContextPath=/sink, Connection=keep-alive, > > Content-Length=12, Host=localhost:29999, > > User-Agent=Apache-HttpClient/5.5 (Java/17.0.15)} > > 2025-09-25T10:32:23.548+03:00 Finished > > 2025-09-25T10:32:23.562+03:00 > > Exchange[DDE7F0CB4616F92-0000000000000000] Spent 106 milliseconds > > 2025-09-25T10:32:24.574+03:00 null onRequestSubmitted: > > org.apache.camel.component.http.HttpEndpoint$1@427b9a63 > > 2025-09-25T10:32:24.576+03:00 Request headers: {Accept-Encoding=gzip, > > x-gzip, deflate, CamelHttpMethod=POST, CamelHttpPath=, > > CamelHttpQuery=null, CamelHttpUri=/sink, > > CamelHttpUrl=http://localhost:29999/sink, > > CamelServletContextPath=/sink, Connection=keep-alive, > > Content-Length=12, Host=localhost:29999, > > User-Agent=Apache-HttpClient/5.5 (Java/17.0.15)} > > 2025-09-25T10:32:24.576+03:00 Finished > > 2025-09-25T10:32:24.577+03:00 null Spent 3 milliseconds > > 2025-09-25T10:32:34.591+03:00 > > Exchange[DDE7F0CB4616F92-0000000000000000] onRequestSubmitted: > > org.apache.camel.component.http.HttpEndpoint$1@427b9a63 > > 2025-09-25T10:32:34.592+03:00 Request headers: {Accept-Encoding=gzip, > > x-gzip, deflate, CamelHttpMethod=POST, CamelHttpPath=, > > CamelHttpQuery=null, CamelHttpUri=/sink, > > CamelHttpUrl=http://localhost:29999/sink, > > CamelServletContextPath=/sink, Connection=keep-alive, > > Content-Length=12, Host=localhost:29999, > > User-Agent=Apache-HttpClient/5.5 (Java/17.0.15)} > > 2025-09-25T10:32:34.593+03:00 Finished > > 2025-09-25T10:32:34.594+03:00 > > Exchange[DDE7F0CB4616F92-0000000000000000] Spent 2 milliseconds > > 2025-09-25T10:32:35.599+03:00 null onRequestSubmitted: > > org.apache.camel.component.http.HttpEndpoint$1@427b9a63 > > 2025-09-25T10:32:35.601+03:00 Request headers: {Accept-Encoding=gzip, > > x-gzip, deflate, CamelHttpMethod=POST, CamelHttpPath=, > > CamelHttpQuery=null, CamelHttpUri=/sink, > > CamelHttpUrl=http://localhost:29999/sink, > > CamelServletContextPath=/sink, Connection=keep-alive, > > Content-Length=12, Host=localhost:29999, > > User-Agent=Apache-HttpClient/5.5 (Java/17.0.15)} > > 2025-09-25T10:32:35.601+03:00 Finished > > 2025-09-25T10:32:35.602+03:00 null Spent 2 milliseconds > > 2025-09-25T10:32:35.606+03:00 Retries exhausted > > org.apache.camel.http.base.HttpOperationFailedException: HTTP > > operation failed invoking http://localhost:29999/sink with statusCode: > > 503 > > > > > > To me this looks like a bug in the retry logic, based on the exchange > > being null in that unwanted call. > > > > I tested this with camel 4.14.0 and 4.10.6 and both behave the same way. > > > > -- > > Veijo Länsikunnas > > > > > -- > Claus Ibsen
