-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Description
Search before reporting
- I searched in the issues and found nothing similar.
Read release policy
- I understand that unsupported versions don't get bug fixes. I will attempt to reproduce the issue on a supported version of Pulsar client and Pulsar broker.
User environment
Broker/Client version: All versions
OS/Java: All
Issue Description
What happened?
The LoadSimulationController class initializes a private static final ExecutorService threadPool (Line 77) using Executors.newCachedThreadPool(). There is no mechanism to shut down this thread pool.
What did I expect to happen?
Resources, especially thread pools, should be managed and released properly when the controller instance is no longer needed or when the application shuts down.
What actually happened instead?
The static thread pool persists for the lifetime of the JVM. Since newCachedThreadPool creates non-daemon threads by default, these active threads prevent the JVM from shutting down cleanly in embedded scenarios and cause thread leakage if the class is loaded/unloaded in a containerized test environment.
Why do I believe this is a bug?
While LoadSimulationController is often used as a CLI tool (where System.exit cleans up resources), it resides in the pulsar-testclient module. If this class is used as a library within a larger automation framework, the unclosed static thread pool leads to Thread Leaks and Platform Resource Exhaustion.
Error messages
N/A (This is a static code analysis finding relating to a resource leak)
Reproducing the issue
-
Inspect the source code of org/apache/pulsar/testclient/LoadSimulationController.java.
-
Locate Line 77: private static final ExecutorService threadPool = Executors.newCachedThreadPool();.
3 Search for usages of threadPool.
- Observe that threadPool.shutdown() or threadPool.shutdownNow() is never called in the entire class.
Additional information
Suggested Fix:
Change threadPool from a static field to an instance field and implement a cleanup method (e.g., close() or shutdown()) to explicitly terminate the ExecutorService.
// Current Code (Leak Risk)
private static final ExecutorService threadPool = Executors.newCachedThreadPool();
// Suggested Code
private final ExecutorService threadPool = Executors.newCachedThreadPool();
public void shutdown() {
threadPool.shutdown();
}
Are you willing to submit a PR?
- I'm willing to submit a PR!