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