feat(FN-1607): add process lifecycle diagnostics and fix resource leaks
- Add process lifecycle diagnostics for dashboard and serve commands - Add SQLite database health check to diagnostics endpoint - Add store listener count diagnostics for debugging subscription leaks - Audit and fix SSE connection management to prevent connection leaks - Audit and fix timer/interval cleanup in engine and CLI shutdown handlers - Fix res.on() call guard for test mocks compatibility - Fix variable declaration ordering in serve.ts - Update memory with diagnostic findings for future debugging
This commit is contained in:
@@ -3,12 +3,18 @@ import type { TaskStore, MissionStore, PluginStore, PluginInstallation, PluginSt
|
||||
import type { AiSessionStore } from "./ai-session-store.js";
|
||||
|
||||
let activeConnections = 0;
|
||||
let highWaterMark = 0;
|
||||
|
||||
/** Returns the current number of active SSE connections. */
|
||||
export function getActiveSSEConnections(): number {
|
||||
return activeConnections;
|
||||
}
|
||||
|
||||
/** Returns the high water mark of SSE connections. */
|
||||
export function getSSEHighWaterMark(): number {
|
||||
return highWaterMark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely write to an SSE response stream.
|
||||
* Returns `true` if the write succeeded, `false` if the connection is dead.
|
||||
@@ -177,6 +183,11 @@ export function createSSE(
|
||||
res.flushHeaders();
|
||||
|
||||
activeConnections++;
|
||||
// Track high water mark and log when new highs are reached
|
||||
if (activeConnections > highWaterMark) {
|
||||
highWaterMark = activeConnections;
|
||||
console.log(`[sse] active connections: ${activeConnections} (high water mark: ${highWaterMark})`);
|
||||
}
|
||||
|
||||
// Send initial heartbeat
|
||||
res.write(": connected\n\n");
|
||||
@@ -415,6 +426,15 @@ export function createSSE(
|
||||
send("event: heartbeat\ndata: \n\n");
|
||||
}, 30_000);
|
||||
|
||||
// Register cleanup on request close (primary path for HTTP/1.1)
|
||||
_req.on("close", cleanup);
|
||||
|
||||
// Also register on response close as a safety net for edge cases
|
||||
// (e.g., proxy timeouts, HTTP/2 stream resets). This ensures cleanup
|
||||
// fires even if the request object doesn't emit "close".
|
||||
// Guard with typeof check for test mocks that may not have on method.
|
||||
if (typeof res.on === "function") {
|
||||
res.on("close", cleanup);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user