feat(background-agent): implement process cleanup for BackgroundManager
Add functionality to manage process cleanup by registering and unregistering signal listeners. This ensures that BackgroundManager instances properly shut down and remove their listeners on process exit. Introduce tests to verify listener removal after shutdown.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, test, expect, beforeEach } from "bun:test"
|
||||
import { afterEach } from "bun:test"
|
||||
import { tmpdir } from "node:os"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import type { BackgroundTask, ResumeInput } from "./types"
|
||||
import { BackgroundManager } from "./manager"
|
||||
@@ -167,7 +168,7 @@ function createBackgroundManager(): BackgroundManager {
|
||||
prompt: async () => ({}),
|
||||
},
|
||||
}
|
||||
return new BackgroundManager({ client, directory: "C:\\tmp" } as unknown as PluginInput)
|
||||
return new BackgroundManager({ client, directory: tmpdir() } as unknown as PluginInput)
|
||||
}
|
||||
|
||||
function getConcurrencyManager(manager: BackgroundManager): ConcurrencyManager {
|
||||
@@ -186,6 +187,18 @@ async function tryCompleteTaskForTest(manager: BackgroundManager, task: Backgrou
|
||||
return (manager as unknown as { tryCompleteTask: (task: BackgroundTask, source: string) => Promise<boolean> }).tryCompleteTask(task, "test")
|
||||
}
|
||||
|
||||
function getCleanupSignals(): Array<NodeJS.Signals | "beforeExit" | "exit"> {
|
||||
const signals: Array<NodeJS.Signals | "beforeExit" | "exit"> = ["SIGINT", "SIGTERM", "beforeExit", "exit"]
|
||||
if (process.platform === "win32") {
|
||||
signals.push("SIGBREAK")
|
||||
}
|
||||
return signals
|
||||
}
|
||||
|
||||
function getListenerCounts(signals: Array<NodeJS.Signals | "beforeExit" | "exit">): Record<string, number> {
|
||||
return Object.fromEntries(signals.map((signal) => [signal, process.listenerCount(signal)]))
|
||||
}
|
||||
|
||||
|
||||
describe("BackgroundManager.getAllDescendantTasks", () => {
|
||||
let manager: MockBackgroundManager
|
||||
@@ -1023,3 +1036,27 @@ describe("BackgroundManager.resume concurrency key", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("BackgroundManager process cleanup", () => {
|
||||
test("should remove listeners after last shutdown", () => {
|
||||
// #given
|
||||
const signals = getCleanupSignals()
|
||||
const baseline = getListenerCounts(signals)
|
||||
const managerA = createBackgroundManager()
|
||||
const managerB = createBackgroundManager()
|
||||
|
||||
// #when
|
||||
const afterCreate = getListenerCounts(signals)
|
||||
managerA.shutdown()
|
||||
const afterFirstShutdown = getListenerCounts(signals)
|
||||
managerB.shutdown()
|
||||
const afterSecondShutdown = getListenerCounts(signals)
|
||||
|
||||
// #then
|
||||
for (const signal of signals) {
|
||||
expect(afterCreate[signal]).toBe(baseline[signal] + 1)
|
||||
expect(afterFirstShutdown[signal]).toBe(baseline[signal] + 1)
|
||||
expect(afterSecondShutdown[signal]).toBe(baseline[signal])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user