Skip to content

Resource Leak: ApplicationManager.listenerExecutor never shut down #426

@sfloess

Description

@sfloess

Description

ApplicationManager creates a cached thread pool for lifecycle listeners but never shuts it down, causing thread leak when ApplicationManager is destroyed.

Location

platform-core/src/main/java/org/flossware/platform/core/ApplicationManager.java:104-110

this.listenerExecutor =
    java.util.concurrent.Executors.newCachedThreadPool(
        r -> {
          Thread t = new Thread(r, "lifecycle-listener");
          t.setDaemon(true);
          return t;
        });

No shutdown() method calls listenerExecutor.shutdown().

Impact

Severity: LOW-MEDIUM

  1. Thread Leak: Each ApplicationManager instance creates threads that never terminate
  2. Resource Leak: Thread pool holds references preventing GC
  3. Mitigated by Daemon: Threads are daemon so JVM can exit, but still wastes resources

While daemon threads allow JVM exit, the thread pool still:

  • Keeps threads alive unnecessarily
  • Holds memory and file descriptors
  • Shows up in thread dumps as "leaked" resources

Recommendation

  1. Add shutdown() method to ApplicationManager
  2. Call listenerExecutor.shutdown() in shutdown()
  3. Wait for termination with timeout
  4. Ensure ClusteredApplicationManager.shutdown() calls super.shutdown()

Verification

Looking at ClusteredApplicationManager.shutdown():

@Override
public void shutdown() {
  // ... removes cluster listener ...
  super.shutdown();  // Good! Calls parent shutdown
}

But ApplicationManager doesn't have a shutdown() method! Need to add it.

Example Fix

// In ApplicationManager class:
public void shutdown() {
  LOGGER.info("Shutting down ApplicationManager");
  
  // Shutdown listener executor
  listenerExecutor.shutdown();
  try {
    if (!listenerExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
      LOGGER.warn("Listener executor did not terminate, forcing shutdown");
      listenerExecutor.shutdownNow();
    }
  } catch (InterruptedException e) {
    listenerExecutor.shutdownNow();
    Thread.currentThread().interrupt();
  }
  
  // Shutdown other resources...
}

Labels

bug, resource-leak

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions