shashank created CAMEL-26050:
--------------------------------

             Summary: camel-thrift - the asynchronous producer (the default) 
never stops its TAsyncClientManager: a selector thread and a selector leak per 
producer start
                 Key: CAMEL-26050
                 URL: https://issues.apache.org/jira/browse/CAMEL-26050
             Project: Camel
          Issue Type: Bug
            Reporter: shashank
            Assignee: shashank


The thrift producer is asynchronous by default ({{synchronous=false}}). 
{{ThriftProducer.doStart}} builds its client with 
{{ThriftUtils.constructAsyncClientInstance}}, which creates a {{new 
TAsyncClientManager()}} each time (a {{TAsyncClientManager#SelectorThread}} and 
an NIO selector). {{doStop}} only closes the transport, and nothing calls 
{{TAsyncClientManager.stop()}} (main 0c1e85c8631c). A route restart creates a 
new producer, so each restart (and each producer evicted from a {{toD}} or 
ProducerTemplate cache) leaks a selector thread and a selector until the JVM 
exits. The module has no test of the asynchronous producer (all producer tests 
use {{synchronous=true}}).

*Fix*: {{ThriftProducer}} creates the manager, passes it to a new 
{{ThriftUtils.constructAsyncClientInstance(..., TAsyncClientManager)}} overload 
and stops it in {{doStop}} (libthrift 0.25.0: {{stop()}} ends the selector 
thread, which closes the selector). The existing 5-argument method is kept (it 
now creates its manager and delegates to the overload; an {{IOException}} of 
{{new TAsyncClientManager()}} now gives the message {{Thrift async client 
manager cannot be created}}). An asynchronous call sent just before the 
producer stops never gets its callback, so its exchange does not complete: 
after {{stop()}} the selector thread only closes the selector (javap 
{{SelectThread.run}}), so a call not started yet or registered on the selector 
gets neither {{onComplete}} nor {{onError}} (on main a call not started yet got 
{{ClosedChannelException}} through {{onError}}, one already registered hung 
too). A graceful shutdown drains inflight exchanges first, so only cache 
eviction or a shutdown timeout can hit this.

*Tests*: new {{ThriftProducerAsyncStopTest}}: 5 restarts of a route with an 
asynchronous ping producer (a ping after each), then a stop; 
{{routeRestartsStopTheClientManagersOfTheStoppedProducers}} fails on main: 
{{selector threads of stopped asynchronous producers ==> expected: <0> but was: 
<5>}}. Unit tests of camel-thrift with the fix: 56 run, 0 failures.

*How it was found*: a per-class thread/fd leak check over module test suites 
and a route restart probe (r75).

*Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x and camel-4.14.x 
(same code). Read, not run.

_Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to