shashank created CAMEL-24951:
--------------------------------

             Summary: Stopping a suspended SEDA route (or the CamelContext) 
with queued messages always waits for the full shutdown timeout
                 Key: CAMEL-24951
                 URL: https://issues.apache.org/jira/browse/CAMEL-24951
             Project: Camel
          Issue Type: Bug
          Components: camel-seda, camel-core
            Reporter: shashank


A suspended {{SedaConsumer}} does not poll, but graceful shutdown waits for it 
to drain its queue:
* {{DefaultShutdownStrategy}} defers the seda consumer ({{deferShutdown}} 
returns true) and loops until inflight + {{getPendingExchangesSize()}} is 0. 
For seda, {{getPendingExchangesSize()}} is the queue size 
(DefaultShutdownStrategy.java:667-716, SedaConsumer.java:88-95).
* After that, {{SedaConsumer.prepareShutdown}} waits on the poll threads' 
latch. The poll threads exit only when {{shutdownPending && queue.isEmpty()}}, 
including in the suspended branch (SedaConsumer.java:175-191, :117).

When the route is suspended and messages were sent to it in the meantime, 
neither wait can finish, so every stop runs into the timeout (default 45 s):
* {{stopRoute(id)}} and {{camelContext.stop()}} take the full timeout and then 
force the shutdown.
* {{stopRoute(id, timeout, unit, true)}} returns false and restarts the route.

Reproduced against 4.23.0-SNAPSHOT, shutdown timeout 5 s, route 
{{from("seda:s")}} suspended with {{suspendRoute("s")}}:
{noformat}
stopRoute,    route suspended, 0 queued : stop took  490 ms, 
timeoutOccurred=false
stopRoute,    route suspended, 3 queued : stop took 5002 ms, 
timeoutOccurred=true, left in queue=2
context.stop, route suspended, 0 queued : stop took  507 ms, 
timeoutOccurred=false
context.stop, route suspended, 3 queued : stop took 5005 ms, 
timeoutOccurred=true
{noformat}
During the forced stop the suspended route still processed one of the queued 
messages.

CAMEL-6390 fixed stopping a suspended seda route with an empty queue. The 
queued-messages case is still open ({{SedaSuspendConsumerStopRouteTest}} stops 
with an empty queue). Routes suspended by a {{RoutePolicy}} such as 
{{ThrottlingInflightRoutePolicy}} end up in this state without user action, and 
route policies are not invoked while Camel is stopping, so they cannot resume 
the consumer either.

Proposed fix: a suspended consumer cannot drain, so do not wait for it.
* {{SedaConsumer.getPendingExchangesSize()}} returns 0 while the consumer is 
suspending or suspended (after the {{purgeWhenStopping}} purge, which is 
unchanged).
* The suspended branch of {{doRun}} breaks out when {{shutdownPending}} is set, 
whether or not the queue is empty.

The queued messages stay in the queue (or are purged by {{purgeWhenStopping}}) 
and are processed if the route is started again while the queue still exists. 
The stop completes in about one poll interval instead of the shutdown timeout, 
and the suspended route no longer processes a message during the forced stop.

Design point for reviewers: the alternative is to drain, i.e. resume suspended 
seda consumers when stopping them. That would process messages on a route the 
user (or a {{RoutePolicy}}) suspended, and the route's own services are 
suspended too, so the patch keeps the messages instead. Today's outcome after 
the timeout is also "not drained", just 45 s later.

A PR with the fix follows, with regression test 
{{SedaSuspendedRouteWithPendingStopTest}} ({{stopRoute}} with 
{{abortAfterTimeout=true}}, and {{context.stop()}}), plus an upgrade-guide note.



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

Reply via email to