shashank created CAMEL-25962:
--------------------------------

             Summary: camel-kamelet - removing a Kamelet's route waits for ever 
while a source Kamelet's threads() pool stays busy, and does not wait for a 
component's own thread pool
                 Key: CAMEL-25962
                 URL: https://issues.apache.org/jira/browse/CAMEL-25962
             Project: Camel
          Issue Type: Improvement
          Components: camel-kamelet
            Reporter: shashank
            Assignee: shashank


With CAMEL-25839 the route of a Kamelet endpoint that is used once and 
discarded ({{toD}}, {{recipientList}}, {{routingSlip}} with {{cacheSize=-1}}, 
{{pollEnrich}}) is stopped and removed on a thread of the Kamelet component. 
The calling route can continue on a thread that the Kamelet's route owns, so 
the removal waits:

* for the calling exchange to be done, when the endpoint is shut down inside 
the producer callback ({{toD}});
* for the thread pools that the route's EIPs created ({{threads()}} and the 
others, tracked with {{LifecycleStrategy.onThreadPoolAdd}} by route id) to be 
idle, in every case.

Two cases are not covered when the endpoint is shut down where the calling 
exchange is not known ({{recipientList}}, {{routingSlip}}, {{pollEnrich}} with 
{{cacheSize=-1}}):

# A thread pool that a component of the route creates for itself, such as the 
worker pool of an asynchronous {{kafka}} producer (the kafka-sink Kamelet, 
{{synchronous=false}} by default). The pool is not created by an EIP, so it has 
no route id. {{KafkaProducer.doStop}} calls {{shutdownGraceful(workerPool, 
shutdownTimeout)}}: it waits for the calling route to leave the worker thread, 
up to 30 s by default, while {{stopRoute}} holds the lock of the CamelContext, 
then interrupts it.
# Executor services that are not a {{ThreadPoolExecutor}} (virtual threads): 
the removal cannot tell whether a thread is still running, so it does not wait.

h3. Possible fix

For 1: attribute the thread pools created while the Kamelet's route is created 
and started (on the thread that creates it) to that route, or check the 
{{ExecutorServiceManager}} for pools whose source is a service of the route. 
For 2: count the running tasks of the route's virtual-thread executors (a 
wrapper that counts them). Alternatively, a core hook that gives a prototype 
endpoint the exchange of the calling route when {{recipientList}}, 
{{routingSlip}} and {{pollEnrich}} shut it down (for example, shut the 
prototype endpoint down from an on-completion of the original exchange), which 
would cover both.

Affected: main, once CAMEL-25839 is merged (before it, the route was never 
removed).

Also (Claus Ibsen, third review of #28260, reproduced with a probe test on 
ee985a1c22): the removal task retries every 100 ms with no limit. For the 
endpoint of a removed route that consumed from a source Kamelet, the first 
attempt runs at once, so with fast steps the pool is usually idle and the route 
is removed (timer every 60 s or every 100 ms: removed within about 1 s). When 
the {{threads()}} pool is busy at that moment (a slow step: HTTP call, 
database; in the probe {{delay(500).syncDelayed()}} with a timer every 100 ms), 
every new message then waits up to 30 s on {{kamelet:sink}} ({{block=true}}), 
the pool never goes idle again, and the Kamelet's route was still there after 
45 s in 3 of 3 runs (434 "still has an active thread: removing it later" TRACE 
lines). Not a regression: before CAMEL-25839 that route was never removed. 
Proposed fix (Claus): skip the idle wait when the endpoint was the input of a 
removed route, since no calling route runs on that pool; otherwise stop the 
route anyway after the shutdown strategy timeout. Test: his 
{{KameletSourceRemovalProbeTest}} (source template with {{threads(2)}} and a 
slow step, consumer route removed at runtime, the Kamelet's route must be gone 
within 30 s).

_Filed with Claude Code on behalf of allthingssecurity._




--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to