fix(#2822): properly cleanup tmux sessions on process shutdown
Two issues fixed: 1. process-cleanup.ts used fire-and-forget void Promise for shutdown handlers — now properly collects and awaits all cleanup promises via Promise.allSettled, with dedup guard to prevent double cleanup 2. TmuxSessionManager was never registered for process cleanup — now registered in create-managers.ts via registerManagerForCleanup Also fixed setTimeout().unref() which could let the process exit before cleanup completes.
This commit is contained in:
@@ -7,6 +7,7 @@ import { BackgroundManager } from "./features/background-agent"
|
|||||||
import { SkillMcpManager } from "./features/skill-mcp-manager"
|
import { SkillMcpManager } from "./features/skill-mcp-manager"
|
||||||
import { initTaskToastManager } from "./features/task-toast-manager"
|
import { initTaskToastManager } from "./features/task-toast-manager"
|
||||||
import { TmuxSessionManager } from "./features/tmux-subagent"
|
import { TmuxSessionManager } from "./features/tmux-subagent"
|
||||||
|
import { registerManagerForCleanup } from "./features/background-agent/process-cleanup"
|
||||||
import { createConfigHandler } from "./plugin-handlers"
|
import { createConfigHandler } from "./plugin-handlers"
|
||||||
import { log } from "./shared"
|
import { log } from "./shared"
|
||||||
import { markServerRunningInProcess } from "./shared/tmux/tmux-utils/server-health"
|
import { markServerRunningInProcess } from "./shared/tmux/tmux-utils/server-health"
|
||||||
@@ -30,6 +31,14 @@ export function createManagers(args: {
|
|||||||
markServerRunningInProcess()
|
markServerRunningInProcess()
|
||||||
const tmuxSessionManager = new TmuxSessionManager(ctx, tmuxConfig)
|
const tmuxSessionManager = new TmuxSessionManager(ctx, tmuxConfig)
|
||||||
|
|
||||||
|
registerManagerForCleanup({
|
||||||
|
shutdown: async () => {
|
||||||
|
await tmuxSessionManager.cleanup().catch((error) => {
|
||||||
|
log("[create-managers] tmux cleanup error during process shutdown:", error)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const backgroundManager = new BackgroundManager(
|
const backgroundManager = new BackgroundManager(
|
||||||
ctx,
|
ctx,
|
||||||
pluginConfig.background_task,
|
pluginConfig.background_task,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ function registerProcessSignal(
|
|||||||
handler()
|
handler()
|
||||||
if (exitAfter) {
|
if (exitAfter) {
|
||||||
process.exitCode = 0
|
process.exitCode = 0
|
||||||
setTimeout(() => process.exit(), 6000).unref()
|
setTimeout(() => process.exit(), 6000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
process.on(signal, listener)
|
process.on(signal, listener)
|
||||||
@@ -32,16 +32,26 @@ export function registerManagerForCleanup(manager: CleanupTarget): void {
|
|||||||
if (cleanupRegistered) return
|
if (cleanupRegistered) return
|
||||||
cleanupRegistered = true
|
cleanupRegistered = true
|
||||||
|
|
||||||
|
let cleanupPromise: Promise<void> | undefined
|
||||||
|
|
||||||
const cleanupAll = () => {
|
const cleanupAll = () => {
|
||||||
|
if (cleanupPromise) return
|
||||||
|
const promises: Promise<void>[] = []
|
||||||
for (const m of cleanupManagers) {
|
for (const m of cleanupManagers) {
|
||||||
try {
|
try {
|
||||||
void Promise.resolve(m.shutdown()).catch((error) => {
|
promises.push(
|
||||||
log("[background-agent] Error during async shutdown cleanup:", error)
|
Promise.resolve(m.shutdown()).catch((error) => {
|
||||||
})
|
log("[background-agent] Error during async shutdown cleanup:", error)
|
||||||
|
})
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log("[background-agent] Error during shutdown cleanup:", error)
|
log("[background-agent] Error during shutdown cleanup:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cleanupPromise = Promise.allSettled(promises).then(() => {})
|
||||||
|
cleanupPromise.then(() => {
|
||||||
|
log("[background-agent] All shutdown cleanup completed")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerSignal = (signal: ProcessCleanupEvent, exitAfter: boolean): void => {
|
const registerSignal = (signal: ProcessCleanupEvent, exitAfter: boolean): void => {
|
||||||
|
|||||||
Reference in New Issue
Block a user