apache / apache/pulsar

[Bug] Static ExecutorService in LoadSimulationController causes resource leak

Open
#25,153 2 comments 0 reactions 0 assignees View on GitHub
type/bug
Dominant language
Java
Stars
15.3k
Forks
3.8k
Avg merge
1d 14h
Merged PRs (30d)
160

Description

### Search before reporting

- [x] I searched in the [issues](https://github.com/apache/pulsar/issues) and found nothing similar.

### Read release policy

- [x] I understand that [unsupported versions](https://pulsar.apache.org/contribute/release-policy/#supported-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

```text
N/A (This is a static code analysis finding relating to a resource leak)
```

### Reproducing the issue

1. Inspect the source code of org/apache/pulsar/testclient/LoadSimulationController.java.

2. Locate Line 77: private static final ExecutorService threadPool = Executors.newCachedThreadPool();.

3 Search for usages of threadPool.

4. 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?

- [x] I'm willing to submit a PR!

Contributor guide

Open the contributing guide

Research direction

Start with pulsar-testclient/src/main/java/org/apache/pulsar/testclient/LoadSimulationController.java, especially the static threadPool declaration around line 77, then search the class for all threadPool usages and lifecycle entry points. Done means the executor is explicitly released when the controller is no longer needed without breaking its existing callers.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.