shashank created CAMEL-25314:
--------------------------------

             Summary: camel-cxf, camel-cxfrs - a suspended consumer keeps 
accepting and routing new requests (graceful shutdown, suspendRoute, route 
policies)
                 Key: CAMEL-25314
                 URL: https://issues.apache.org/jira/browse/CAMEL-25314
             Project: Camel
          Issue Type: Bug
          Components: camel-cxf, camel-cxfrs
            Reporter: shashank


Since CAMEL-12870 {{CxfConsumer}} and {{CxfRsConsumer}} implement 
{{Suspendable}}: {{DefaultShutdownStrategy}} suspends them instead of stopping 
them, defers their shutdown until no exchange is inflight, and the CXF server 
stays up so the requests in flight can still send their responses. But neither 
consumer has suspend logic, and their invokers 
({{CxfConsumer.CxfConsumerInvoker.invoke}}, {{CxfRsInvoker.performInvocation}}) 
never check the status, so a suspended consumer keeps accepting and routing 
*new* requests:

* graceful shutdown: with a steady flow of requests the number of inflight 
exchanges does not drop to 0, so the route (or the CamelContext) is only 
stopped at the shutdown timeout, and the requests in flight at that moment are 
forced; the requests accepted during the shutdown are processed by a stopping 
application;
* {{suspendRoute}} (route controller, JMX) and the route policies that suspend 
the consumer ({{ThrottlingInflightRoutePolicy}}, 
{{ThrottlingExceptionRoutePolicy}}): nothing is held back.

The HTTP consumers (servlet, jetty, undertow, netty-http, platform-http) answer 
503 (Service Unavailable) while they are suspended.

h3. Reproduction

{{CxfConsumerSuspendTest}} (camel-cxf-soap) and {{CxfRsConsumerSuspendTest}} 
(camel-cxf-rest), on main:

{noformat}
CxfConsumerSuspendTest.testSuspendedRouteRejectsRequests: suspendRoute, then a 
request
  A suspended route must not accept a request ==> Expected java.lang.Exception 
to be thrown, but nothing was thrown.
CxfConsumerSuspendTest.testGracefulStopCompletesInflightAndRejectsNewRequests: 
request A blocks in the route,
  stopRoute (graceful) suspends the consumer, request B is sent
  A request received while stopping must be rejected ==> Expected 
java.lang.Exception to be thrown, but nothing was thrown.
CxfRsConsumerSuspendTest.testSuspendedRouteRejectsRequests:
  A suspended route must answer 503 ==> expected: <503> but was: <200>
CxfRsConsumerSuspendTest.testGracefulStopCompletesInflightAndRejectsNewRequests 
(asynchronous request in flight):
  A request received while stopping must be rejected ==> expected: <503> but 
was: <200>
{noformat}

With the fix the rejected requests get HTTP 503, request A (asynchronous, its 
continuation resumes after the suspend) still gets its response, and the route 
stops. No sleeps: latches, Awaitility.

The defect was found with a TLA+ model of the consumer under a graceful 
shutdown / route suspend, with synchronous and asynchronous (continuation) 
requests: "a suspended consumer takes no new work" is violated in 3 steps 
(suspend, a request arrives, it is admitted). The property of CAMEL-12870, "the 
consumer is only stopped when nothing is inflight", holds on the current code 
and with the fix. A fix that also rejected resumed continuations would lose the 
responses of the requests in flight (shown by the model: "an admitted request 
gets its response" violated), so the fix only rejects new invocations.

h3. Proposed fix

In both invokers, reject a new invocation (synchronous, or a continuation that 
{{isNew()}}) while the consumer {{isSuspendingOrSuspended()}}: {{CxfConsumer}} 
throws a {{Fault}} with status code 503 (CXF's {{PhaseInterceptorChain}} logs 
it at WARN with the stack trace, as it does for any undeclared fault, e.g. a 
route failure; making it quieter would need 
{{FaultMode.CHECKED_APPLICATION_FAULT}}, which also drives WS-Addressing, WS-RM 
and the management counters, so it is left as is), {{CxfRsInvoker}} returns a 
503 {{Response}} (a {{WebApplicationException}} is logged at WARN with its 
stack trace by CXF's {{WebApplicationExceptionMapper}}, once per rejected 
request). {{CxfRsInvoker}} still skips the continuation lookup for a sub 
resource locator invocation (its sub resource method is checked next). A 
resumed continuation is always completed. CAMEL-12870 only added {{implements 
Suspendable}} (no discussion on the ticket); its purpose, completing the 
requests in flight, is kept.

Upgrade guide note, as a {{====}} subsection of the existing {{=== camel-cxf}} 
section (a suspended CXF consumer answers 503 to new requests).

With the fix the new tests and the camel-cxf-soap (168, 2 skipped), 
camel-cxf-rest (51), camel-cxf-spring-soap (161, 3 skipped) and 
camel-cxf-spring-rest (111) suites pass.

Affected: 4.14.x, 4.18.x and main (same code, GitHub contents API), since 
2.21.3 / 2.22.2 / 2.23.0.

Duplicate check (2026-10-04): JIRA "cxf" with 503 / "graceful shutdown" / 
suspended (CAMEL-12870 above; CAMEL-18528 SpringBus shutdown order; CAMEL-24179 
continuation timeout race; none about new requests while suspended). GitHub 
pull requests "cxf suspend", "CxfRsInvoker": none about this; the open draft 
#22358 (CAMEL-20009, getOut replacement) changes other lines of 
{{CxfRsInvoker}} (imports, {{prepareExchange}}).

_Filed with Claude Code on behalf of allthingssecurity._




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

Reply via email to