[ 
https://issues.apache.org/jira/browse/CAMEL-26536?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Work on CAMEL-26536 started by shashank.
----------------------------------------
> camel-jms - with asyncStopListener=true, a JmsConsumer stopped and started 
> again ends up started without a running listener container
> -------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-26536
>                 URL: https://issues.apache.org/jira/browse/CAMEL-26536
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-jms
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>
> Found with a TLA+ model of {{JmsConsumer}} with {{asyncStartListener}} / 
> {{asyncStopListener}} (the lifecycle thread, the asynchronous stop task and 
> the asynchronous start task on the component's pool), cross-checked with a 
> SPIN model, then reproduced on the real classes.
> With {{asyncStopListener=true}}, {{JmsConsumer.doStop}} submits 
> {{stopAndDestroyListenerContainer()}} to the component's thread pool and 
> returns, with {{listenerContainer}} still set. If the same consumer is 
> started again before that task has run (route policies that stop and start 
> the consumer, such as the leader-election policies {{HazelcastRoutePolicy}} 
> and {{MasterRoutePolicy}} of camel-zookeeper-master, the JMX start/stop 
> operations of the consumer, or code that calls {{stop()}} / {{start()}} on 
> it), {{doStart}} sees the old listener container, does not create a new one, 
> and initializes and starts it again. The stop task then reads the field, 
> stops and destroys that container, and sets {{listenerContainer}} to null. 
> The consumer reports Started but has no listener container and consumes 
> nothing, with no error logged. If the stop task nulls the field while 
> {{doStart}} is between its null check and {{afterPropertiesSet()}}, the start 
> fails with a NullPointerException instead. The stop task also shuts down the 
> private thread pool stored in {{executorService}}, which can be the pool of a 
> listener container created by the new start.
> Short trace of the model:
> {noformat}
> 1 lifecycle : doStop  -> listenerContainer = C1, submit stop task          
> (JmsConsumer:216-219)
> 2 lifecycle : doStart -> listenerContainer != null, keep C1                 
> (:149)
> 3 lifecycle : C1.afterPropertiesSet(); C1.start(); initialized = true     
> (:177-189)
> 4 stop task : listenerContainer.stop(); listenerContainer.destroy()       
> (:195-196)  -> C1 not running
> 5 stop task : listenerContainer = null; initialized = false               
> (:203-205)
>   -> consumer Started, no listener container
> {noformat}
> With {{asyncStartListener=true}} as well, the start task works on whatever 
> the field holds when it runs: it can start the container the stop task 
> destroys, hit the null field (NPE logged as "ignored"), or initialize a newer 
> container a second time.
> The real-class test holds the tasks the consumer submits to the pool and runs 
> them in a chosen order: stopping and starting the consumer with the stop task 
> pending leaves {{getListenerContainer().isRunning()}} false and the next 
> message is not consumed. Without hooks, 30 stop/start cycles of the consumer 
> with the real pool (in-VM Artemis) ended 30 times without a running listener 
> container (27 started without a listener, 3 starts failed with the NPE).
> A route restart ({{restartRoute}}, {{stopRoute}} + {{startRoute}}) is not 
> affected, as the route creates a new consumer when it starts again.
> *Proposal:* {{doStop}} detaches the listener container under a lock of the 
> consumer (the container, its private thread pool and the {{initialized}} flag 
> are taken and cleared at once), and the stop task stops and destroys only the 
> container (and pool) it was given, so a start that runs before the stop task 
> creates a new listener container. {{doStart}} hands the container it created 
> to the start task, which does nothing if the consumer no longer uses it, and 
> after starting it checks again under the lock and stops and destroys it if 
> the consumer was stopped meanwhile.
> Affected: main, 4.23.x, 4.22.x (the same {{JmsConsumer}} code), 4.18.x, 
> 4.14.x (the same bug; {{initialized}} is set in {{doStart}} there).
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to