Repository navigation
[fix][client] Shut down admin TLS factory executor on resolution failure - #27509
HimanshuJha-2005 wants to merge 1 commit into
Conversation
codelipenghui
left a comment
There was a problem hiding this comment.
The runtime fix is correct and minimal. When ClientTlsFactorySupport.resolveClientTlsFactory throws, resolveNewTlsFactory now shuts down its private pulsar-admin-tls-factory executor. That matches AsyncHttpConnectorProvider.sharedTlsFactory() and the PIP-478 ownership split: the resolver closes the factory it initialized, the creator stops the executor, and ownership stays none(), so nothing is closed twice. The success path and the exception types callers see are unchanged.
I verified this before and after. With the main hunk reverted, the new test fails because thread pulsar-admin-tls-factory-2-1 is still alive. With the PR code it passes, and AsyncHttpConnectorTest (13 tests) and AdminTlsFactoryLifecycleTest (9 tests) also pass.
One blocker: the new test's imports break checkstyle's ImportOrder rule. CI runs checkstyleTest, so the PR fails CI as-is. Fix the import order (and switch the two inline fully qualified names to imports while there) and the change is ready.
| import java.util.Optional; | ||
| import org.apache.pulsar.tls.PulsarTlsFactory; | ||
| import org.apache.pulsar.tls.TlsFactoryInitContext; | ||
| import org.apache.pulsar.tls.TlsHandle; | ||
| import org.apache.pulsar.tls.TlsPurpose; |
There was a problem hiding this comment.
New test imports break checkstyle ImportOrder, which CI enforces via checkstyleTest
Any CI run, or locally './gradlew :pulsar-client-admin-original:checkstyleTest'. The "Build, check licenses and code style" step in .github/workflows/pulsar-ci.yaml:196 runs './gradlew assemble rat spotlessCheck checkstyleMain checkstyleTest'. A required CI step fails every time, so the PR cannot merge as-is. The description says CI passes, but only spotlessCheck was run locally, and spotless does not check import order.
Ran ':pulsar-client-admin-original:checkstyleTest' at head 84748f5. The task FAILED with two errors:
- 'AsyncHttpConnectorTest.java:49:1: Wrong lexicographical order for 'java.util.Optional' import. Should be before 'java.util.concurrent.atomic.AtomicReference'. [ImportOrder]'
- 'AsyncHttpConnectorTest.java:54:1: Wrong lexicographical order for 'lombok.Cleanup' import. Should be before 'org.apache.pulsar.tls.TlsPurpose'. [ImportOrder]'
buildtools/src/main/resources/pulsar/checkstyle.xml:124-132 sets ImportOrder to error severity, with non-static imports in one ASCII-sorted group. ':pulsar-client-admin-original:checkstyleMain' passes, so only the test file is affected.
Put 'import java.util.Optional;' right after 'import java.util.List;'. Move the four 'org.apache.pulsar.tls.' imports after 'import org.apache.pulsar.common.util.FutureUtil;', so 'lombok.Cleanup' comes before all 'org.' imports. While editing the imports, add 'import java.util.concurrent.CountDownLatch;' (after 'CopyOnWriteArrayList') and 'import java.util.function.Consumer;' (after 'atomic.AtomicReference'), and use the simple names at lines 545 and 569 instead of the inline fully qualified names, per the AGENTS.md style rule. Then re-run './gradlew :pulsar-client-admin-original:checkstyleTest'.
Fixes apache#26427 In AsyncHttpConnector.resolveNewTlsFactory, a single-thread scheduled executor is allocated for the pulsar-admin-tls-factory thread. When ClientTlsFactorySupport.resolveClientTlsFactory throws an exception during resolution or initialization, the executor is never shut down. Because Netty's DefaultThreadFactory creates non-daemon threads by default, this leaks the thread and prevents JVM termination. Wrap the factory resolution in a try-catch block to ensure executor.shutdownNow() is called if resolution throws, mirroring the error handling in AsyncHttpConnectorProvider.
84748f5 to
3e8dd43
Compare
|
Thanks for the review @codelipenghui! Fixed the import order to satisfy checkstyle and replaced the inline fully qualified names with imports. Re-verified that :pulsar-client-admin-original:checkstyleTest and spotlessCheck both pass cleanly. |
Thanks for the PR. building reference with
the shortcut for To run full CI pipeline in your own fork, please read Personal CI. |
Fixes #26427
Motivation
In
AsyncHttpConnector.resolveNewTlsFactory, a single-thread scheduled executor is created withDefaultThreadFactory("pulsar-admin-tls-factory"):When
AsyncHttpConnectoris created via its public constructors (which supplyTlsFactoryOwnership.none()), ifClientTlsFactorySupport.resolveClientTlsFactorythrows an exception (e.g. invalid TLS parameters, unresolvable custom TLS factory, or failing factory initialization),this.tlsFactoryOwnershipis never assigned. Consequently, the constructor's cleanup path (releasePartialResources) cannot close the executor.Because Netty's
DefaultThreadFactorycreates non-daemon threads by default, the allocatedpulsar-admin-tls-factorythread leaks and prevents the JVM from exiting.AsyncHttpConnectorProvider.sharedTlsFactory()already guards the identical allocation with a try-catch block shutting down the executor on failure.Modifications
AsyncHttpConnector.resolveNewTlsFactory, wrapClientTlsFactorySupport.resolveClientTlsFactoryin atry ... catch (Throwable t)block and invokeexecutor.shutdownNow()before rethrowing.testResolveNewTlsFactoryShutdownExecutorOnFailuretoAsyncHttpConnectorTestverifying that when TLS factory resolution fails, the allocated executor thread is promptly terminated.Verifying this change
This change added tests and can be verified as follows:
testResolveNewTlsFactoryShutdownExecutorOnFailureinAsyncHttpConnectorTest, verifying the thread leak is eliminated when factory resolution throws.:pulsar-client-admin-original:spotlessCheckpasses cleanly.Does this pull request potentially affect one of the following parts:
If the box was checked, please highlight the changes