shutdownManager.ts in mcp-mermaid codebase.
In this article, we review shutdownManager.ts in mcp-mermaid codebase. We will look at:
-
What is shutdownManager.ts?
-
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.