This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 91bae2d98372 CAMEL-25279: camel-knative - a consumer without reply 
must not answer 204 when the exchange failed (#27308)
91bae2d98372 is described below

commit 91bae2d983729a5018aeb4830d6bd332325af969
Author: allthingssecurity <[email protected]>
AuthorDate: Sat Oct 3 13:46:47 2026 +0530

    CAMEL-25279: camel-knative - a consumer without reply must not answer 204 
when the exchange failed (#27308)
    
    With `reply=false` the Knative HTTP consumer never has a response body, and 
without a body it always set `204 No Content`, overwriting the 500 it had just 
computed for a failed exchange. Knative takes a 2xx answer as a delivered 
event, so an event whose route failed was not retried (nor sent to a dead 
letter sink). CAMEL-24428 fixed the same overwrite for `muteException` with 
`reply=true`.
    This change: without a body the consumer sets 204 only when the exchange 
did not fail; a failed exchange keeps its error status, with an empty body. The 
upgrade guide for 4.23 gets a short note.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../knative/http/KnativeHttpConsumer.java          |  6 +++-
 .../component/knative/http/KnativeHttpTest.java    | 39 ++++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc    |  6 ++++
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git 
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
 
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
index 2688d5ebd18c..47edde4d5c75 100644
--- 
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
+++ 
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
@@ -261,7 +261,11 @@ public class KnativeHttpConsumer extends DefaultConsumer {
                                 if (body != null) {
                                     request.response().end(body);
                                 } else {
-                                    request.response().setStatusCode(204);
+                                    // 204 tells the caller that the event has 
been delivered: a failed exchange
+                                    // without reply keeps its error status, 
so that the event is sent again
+                                    if (!exchange.isFailed()) {
+                                        request.response().setStatusCode(204);
+                                    }
                                     request.response().end();
                                 }
                             } catch (Exception e) {
diff --git 
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
 
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
index c9080f3c5893..16b049875743 100644
--- 
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
+++ 
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
@@ -1399,6 +1399,45 @@ public class KnativeHttpTest {
                 .body(is(emptyOrNullString()));
     }
 
+    /**
+     * Without a reply the consumer answers 204 No Content, which tells 
Knative that the event has been delivered: a
+     * failed exchange must keep its error status, or the event is lost.
+     */
+    @ParameterizedTest
+    @EnumSource(CloudEvents.class)
+    void testNoReplyFailure(CloudEvent ce) throws Exception {
+        configureKnativeComponent(
+                context,
+                ce,
+                sourceChannel(
+                        "channel",
+                        Map.of(
+                                Knative.KNATIVE_CLOUD_EVENT_TYPE, 
"org.apache.camel.event",
+                                Knative.CONTENT_TYPE, "text/plain")));
+
+        RouteBuilder.addRoutes(context, b -> {
+            b.from("knative:channel/channel?reply=false")
+                    .throwException(new IllegalStateException("Forced"));
+        });
+
+        context.start();
+
+        given()
+                .body("test")
+                .header(Exchange.CONTENT_TYPE, "text/plain")
+                .header(httpAttribute(ce, 
CloudEvent.CAMEL_CLOUD_EVENT_VERSION), ce.version())
+                .header(httpAttribute(ce, CloudEvent.CAMEL_CLOUD_EVENT_TYPE), 
"org.apache.camel.event")
+                .header(httpAttribute(ce, CloudEvent.CAMEL_CLOUD_EVENT_ID), 
"myEventID")
+                .header(httpAttribute(ce, CloudEvent.CAMEL_CLOUD_EVENT_TIME),
+                        
DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()))
+                .header(httpAttribute(ce, 
CloudEvent.CAMEL_CLOUD_EVENT_SOURCE), "/somewhere")
+                .when()
+                .post()
+                .then()
+                .statusCode(500)
+                .body(is(emptyOrNullString()));
+    }
+
     @ParameterizedTest
     @EnumSource(CloudEvents.class)
     void testNoReplyMeta(CloudEvent ce) throws Exception {
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index de469765b4f5..c1a368e51a05 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -2156,6 +2156,12 @@ Deployments that relied on the previous behaviour — a 
development cluster with
 certificate, for example — must either configure a truststore or set 
`camel.knative.client.ssl.trust.all`
 explicitly. `KnativeOidcClientOptions` extends this class and is affected the 
same way.
 
+A Knative consumer with `reply=false` now answers a failed exchange with its 
error status instead of `204 No Content`.
+
+Such a consumer answered `204 No Content` to every request, also when the 
route failed, so Knative took the event as
+delivered and did not send it again. A failed exchange now keeps its status 
(500, or the `CamelHttpResponseCode`
+header the route set) with an empty body, as with `reply=true`. Successful 
exchanges still get `204 No Content`.
+
 === camel-paho
 
 When `automaticReconnect=true` and the MQTT broker reconnects, the consumer 
now restarts the route

Reply via email to