Croway opened a new pull request, #26584:
URL: https://github.com/apache/camel/pull/26584

   ## Summary
   
   `CamelServlet.doServiceAsync()` (used when `async=true` and no `executorRef` 
is configured — the simplest, most common async servlet setup) called 
`AsyncContext.complete()` unconditionally right after `doService()` returned, 
discarding the `CompletionStage` that `doExecute()` returns when the route's 
processor genuinely completes on another thread 
(`AsyncProcessor.processAsync()`).
   
   This races the servlet container's async completion against the later 
`afterProcess()`/`writeResponse()` call:
   * On Tomcat this throws `IllegalStateException: The response object has been 
recycled and is no longer associated with this facade`.
   * Otherwise, the async context completes with whatever was (or wasn't) 
written yet, and the client gets a stale/empty response while the route keeps 
running in the background.
   
   Reproduced without any third-party client library: a route with 
`.delay(300).asyncDelayed()` behind `async=true`/no `executorRef`, serviced 
through an embedded Undertow container, returns `HTTP 200` with an **empty 
body** every time on `main` before this fix.
   
   The sibling path used when `executorRef` **is** configured 
(`doAsyncExecution()`) already does this correctly — it chains 
`AsyncContext.complete()` onto `promise.whenComplete(...)`. This bug predates 
4.21/4.22: it was introduced by CAMEL-11731 (Camel 3.7) when true async 
processing was added to `doExecute()`, without updating the no-`executorRef` 
`doServiceAsync()` dispatch path to match.
   
   ## Changes
   
   * `doService()` now returns the `CompletionStage<?>` from `doExecute()` 
instead of discarding it.
   * `doServiceAsync()` completes the `AsyncContext` only once that stage 
completes, mirroring `doAsyncExecution()`.
   * Fixed the same `context.complete()` gap in `doAsyncExecution()`'s error 
branch (it was unreachable, since `onError()` always throws — so a synchronous 
exception there never completed the `AsyncContext`, only timed out).
   * `CamelContinuationServlet` (`camel-jetty`) and `CamelWebSocketServlet` 
(`camel-atmosphere-websocket`) are updated only for the new signature (`return 
null`) — both already manage their own async completion internally and are 
unaffected in behavior.
   * Added `ServletAsyncNoExecutorRefRaceTest` reproducing the bug with a 
genuinely-async route step, independent of any external service.
   
   ## Test plan
   
   - [x] New test `ServletAsyncNoExecutorRefRaceTest` fails before the fix 
(empty body), passes after
   - [x] `camel-servlet` full test suite passes
   - [x] `camel-jetty` `*Continuation*`/`*Async*` tests pass (no regression 
from the `CamelContinuationServlet` signature change)
   
   Fixes CAMEL-24811.
   
   _Claude Code on behalf of Croway_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to