Blog
shutdownManager.ts in mcp-mermaid codebase.

shutdownManager.ts in mcp-mermaid codebase.

In this article, we review shutdownManager.ts in mcp-mermaid codebase. We will look at:

  1. What is shutdownManager.ts?

  2. Functions defined.

What is shutdownManager.ts?

I found the following comment in mcp-mermaid/src/utils/shutdownManager.ts


/**
 * Centralized shutdown manager for handling cleanup and graceful shutdown
 */

So, this is basically used to cleanup and gracefully shutdown, but what exactly is getting cleaned up? To understand that we will have to pick some references from the mcp-mermaid codebase.

registerCleanup

Example 1:

In mcp-mermaid/src/server.ts, you will find the below code:

// Register server cleanup with shutdown manager
shutdownManager.registerCleanup(createServerCleanup(server));

Example 2:

In mcp-mermaid/src/services/stdio.ts, you will find the below code:

// Register transport cleanup
shutdownManager.registerCleanup(createTransportCleanup(transport));

But how is actual cleanup happening? If you take a closer look at the below code in mcp-mermaid/src/utils/httpServer.ts:

// Setup signal handlers only once
shutdownManager.setupSignalHandlers();

To understand how calling this once cleans up, you will have to understand the functions defined in ShutdownManager.

Functions defined

registerCleanup

export class ShutdownManager {
  private cleanupHandlers: Array<() => void | Promise<void>> = [];
  private isShuttingDown = false;

  /**
   * Register a cleanup handler
   */
  registerCleanup(handler: () => void | Promise<void>): void {
    this.cleanupHandlers.push(handler);
  }

cleanup

async cleanup(): Promise<void> {
    if (this.isShuttingDown) {
      Logger.warn("Shutdown already in progress, forcing exit...");
      process.exit(1);
    }

    this.isShuttingDown = true;
    Logger.info("🔄 Shutting down gracefully...");

    // Execute all cleanup handlers with timeout
    const cleanupPromises = this.cleanupHandlers.map(async (handler) => {
      try {
        await Promise.race([
          handler(),
          new Promise((_, reject) =>
            setTimeout(() => reject(new Error("Cleanup timeout")), 3000),
          ),
        ]);
      } catch (error) {
        Logger.error("Error during cleanup", error);
      }
    });

    await Promise.all(cleanupPromises);
    Logger.success("Cleanup completed");
    process.exit(0);
  }

setupSignalHandlers

/**
* Setup signal handlers for graceful shutdown
*/
setupSignalHandlers(): void {
  // Remove any existing listeners to avoid duplicates
  process.removeAllListeners("SIGINT");
  process.removeAllListeners("SIGTERM");
  
  process.once("SIGINT", this.cleanup.bind(this));
  process.once("SIGTERM", this.cleanup.bind(this));
}

setupSignalHandlers is setup once and calls the cleanup function when a process terminates, which in this case is, server I am assuming and the process events that are registered here are SIGINT and SIGTERM.

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

Want to learn from open-source? Solve challenges inspired by open-source projects.

References:

  1. https://github.com/hustcc/mcp-mermaid/blob/main/src/utils/shutdownManager.ts#L13

  2. https://github.com/hustcc/mcp-mermaid/blob/ee4b38216771306d48c2ed31f04ce3f2975cc97a/src/server.ts#L40

  3. https://github.com/hustcc/mcp-mermaid/blob/ee4b38216771306d48c2ed31f04ce3f2975cc97a/src/services/stdio.ts#L10

We use cookies
We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking "Accept", you agree to our use of cookies.

Learn more