sensorium-mcp 3.1.0-refactor.18 → 3.1.0-refactor.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/agent-settings.d.ts +6 -0
- package/dist/config/agent-settings.d.ts.map +1 -1
- package/dist/config/agent-settings.js +22 -0
- package/dist/config/agent-settings.js.map +1 -1
- package/dist/config/detail-grant.d.ts +39 -0
- package/dist/config/detail-grant.d.ts.map +1 -0
- package/dist/config/detail-grant.js +61 -0
- package/dist/config/detail-grant.js.map +1 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -3
- package/dist/config/index.js.map +1 -1
- package/dist/config/settings-store.d.ts.map +1 -1
- package/dist/config/settings-store.js +2 -3
- package/dist/config/settings-store.js.map +1 -1
- package/dist/dashboard/routes/copilot.d.ts.map +1 -1
- package/dist/dashboard/routes/copilot.js +17 -1
- package/dist/dashboard/routes/copilot.js.map +1 -1
- package/dist/dashboard/routes/threads-read.d.ts.map +1 -1
- package/dist/dashboard/routes/threads-read.js +15 -3
- package/dist/dashboard/routes/threads-read.js.map +1 -1
- package/dist/dashboard/routes/threads.d.ts.map +1 -1
- package/dist/dashboard/routes/threads.js +13 -4
- package/dist/dashboard/routes/threads.js.map +1 -1
- package/dist/dashboard/routes.d.ts.map +1 -1
- package/dist/dashboard/routes.js +11 -4
- package/dist/dashboard/routes.js.map +1 -1
- package/dist/dashboard/spa.html +11 -11
- package/dist/data/daily-marker.js +3 -3
- package/dist/data/daily-marker.js.map +1 -1
- package/dist/data/file-storage.d.ts.map +1 -1
- package/dist/data/file-storage.js +3 -3
- package/dist/data/file-storage.js.map +1 -1
- package/dist/data/memory/bootstrap.d.ts.map +1 -1
- package/dist/data/memory/bootstrap.js +2 -3
- package/dist/data/memory/bootstrap.js.map +1 -1
- package/dist/data/memory/migration-runner.d.ts.map +1 -1
- package/dist/data/memory/migration-runner.js +2 -3
- package/dist/data/memory/migration-runner.js.map +1 -1
- package/dist/data/memory/schema.js +2 -2
- package/dist/data/memory/schema.js.map +1 -1
- package/dist/index.js +54 -21
- package/dist/index.js.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +21 -2
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/paths.d.ts +29 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +36 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/server/factory.js +16 -6
- package/dist/server/factory.js.map +1 -1
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/http-server.js +22 -7
- package/dist/server/http-server.js.map +1 -1
- package/dist/services/agent-spawn.service.d.ts +3 -3
- package/dist/services/agent-spawn.service.d.ts.map +1 -1
- package/dist/services/agent-spawn.service.js +30 -9
- package/dist/services/agent-spawn.service.js.map +1 -1
- package/dist/services/background-runner.d.ts.map +1 -1
- package/dist/services/background-runner.js +22 -12
- package/dist/services/background-runner.js.map +1 -1
- package/dist/services/broker-client.d.ts +209 -0
- package/dist/services/broker-client.d.ts.map +1 -0
- package/dist/services/broker-client.js +359 -0
- package/dist/services/broker-client.js.map +1 -0
- package/dist/services/claude-spawn.service.d.ts +1 -1
- package/dist/services/claude-spawn.service.d.ts.map +1 -1
- package/dist/services/claude-spawn.service.js +25 -25
- package/dist/services/claude-spawn.service.js.map +1 -1
- package/dist/services/codex-spawn.service.d.ts +1 -1
- package/dist/services/codex-spawn.service.d.ts.map +1 -1
- package/dist/services/codex-spawn.service.js +19 -24
- package/dist/services/codex-spawn.service.js.map +1 -1
- package/dist/services/copilot-spawn.service.d.ts +1 -1
- package/dist/services/copilot-spawn.service.d.ts.map +1 -1
- package/dist/services/copilot-spawn.service.js +45 -36
- package/dist/services/copilot-spawn.service.js.map +1 -1
- package/dist/services/dispatcher/broker.d.ts +4 -3
- package/dist/services/dispatcher/broker.d.ts.map +1 -1
- package/dist/services/dispatcher/broker.js +23 -11
- package/dist/services/dispatcher/broker.js.map +1 -1
- package/dist/services/dispatcher/lock.js +2 -2
- package/dist/services/dispatcher/lock.js.map +1 -1
- package/dist/services/dispatcher/poller.d.ts.map +1 -1
- package/dist/services/dispatcher/poller.js +24 -5
- package/dist/services/dispatcher/poller.js.map +1 -1
- package/dist/services/flight-recorder.service.d.ts.map +1 -1
- package/dist/services/flight-recorder.service.js +43 -5
- package/dist/services/flight-recorder.service.js.map +1 -1
- package/dist/services/keeper.service.d.ts +9 -0
- package/dist/services/keeper.service.d.ts.map +1 -1
- package/dist/services/keeper.service.js +158 -34
- package/dist/services/keeper.service.js.map +1 -1
- package/dist/services/maintenance-signal.d.ts.map +1 -1
- package/dist/services/maintenance-signal.js +2 -3
- package/dist/services/maintenance-signal.js.map +1 -1
- package/dist/services/process.service.d.ts +76 -61
- package/dist/services/process.service.d.ts.map +1 -1
- package/dist/services/process.service.js +224 -608
- package/dist/services/process.service.js.map +1 -1
- package/dist/services/reconnect-snapshot.service.js +2 -2
- package/dist/services/reconnect-snapshot.service.js.map +1 -1
- package/dist/services/scheduler.d.ts +1 -0
- package/dist/services/scheduler.d.ts.map +1 -1
- package/dist/services/scheduler.js +69 -14
- package/dist/services/scheduler.js.map +1 -1
- package/dist/services/self-update.service.d.ts +14 -3
- package/dist/services/self-update.service.d.ts.map +1 -1
- package/dist/services/self-update.service.js +143 -74
- package/dist/services/self-update.service.js.map +1 -1
- package/dist/services/spawn-common.d.ts +49 -23
- package/dist/services/spawn-common.d.ts.map +1 -1
- package/dist/services/spawn-common.js +262 -47
- package/dist/services/spawn-common.js.map +1 -1
- package/dist/services/spawn-exit-watcher.d.ts +43 -0
- package/dist/services/spawn-exit-watcher.d.ts.map +1 -0
- package/dist/services/spawn-exit-watcher.js +127 -0
- package/dist/services/spawn-exit-watcher.js.map +1 -0
- package/dist/services/thread-health.service.d.ts +1 -1
- package/dist/services/thread-health.service.d.ts.map +1 -1
- package/dist/services/thread-health.service.js +11 -7
- package/dist/services/thread-health.service.js.map +1 -1
- package/dist/services/thread-lifecycle.service.js +2 -2
- package/dist/services/thread-lifecycle.service.js.map +1 -1
- package/dist/services/worker-cleanup.service.d.ts.map +1 -1
- package/dist/services/worker-cleanup.service.js +25 -99
- package/dist/services/worker-cleanup.service.js.map +1 -1
- package/dist/test-bootstrap.d.ts +39 -0
- package/dist/test-bootstrap.d.ts.map +1 -0
- package/dist/test-bootstrap.js +78 -0
- package/dist/test-bootstrap.js.map +1 -0
- package/dist/tools/defs/session-defs.js +1 -1
- package/dist/tools/defs/session-defs.js.map +1 -1
- package/dist/tools/defs/utility-defs.d.ts.map +1 -1
- package/dist/tools/defs/utility-defs.js +4 -3
- package/dist/tools/defs/utility-defs.js.map +1 -1
- package/dist/tools/delegate-tool.d.ts +1 -1
- package/dist/tools/delegate-tool.d.ts.map +1 -1
- package/dist/tools/delegate-tool.js +37 -6
- package/dist/tools/delegate-tool.js.map +1 -1
- package/dist/tools/session-tools.d.ts.map +1 -1
- package/dist/tools/session-tools.js +26 -9
- package/dist/tools/session-tools.js.map +1 -1
- package/dist/tools/utility-tools.js +1 -1
- package/dist/tools/utility-tools.js.map +1 -1
- package/dist/tools/wait/message-delivery.d.ts.map +1 -1
- package/dist/tools/wait/message-delivery.js +1 -2
- package/dist/tools/wait/message-delivery.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit watching for broker-spawned agents (Phase 3).
|
|
3
|
+
*
|
|
4
|
+
* A locally-spawned child reports its death through `child.on("exit")`; a
|
|
5
|
+
* broker-spawned process is the SUPERVISOR's child, so the MCP has no handle to
|
|
6
|
+
* wait on. Communication is strictly one-way (MCP → supervisor — hard
|
|
7
|
+
* criterion), so the supervisor cannot push the event either. Instead this
|
|
8
|
+
* watcher polls.
|
|
9
|
+
*
|
|
10
|
+
* Liveness is JOB-based, keyed on the THREAD — never the raw pid the broker
|
|
11
|
+
* returned at spawn. On Windows both claude.exe and copilot.exe are LAUNCHERS:
|
|
12
|
+
* they fork the real agent (a node child with a different pid) into the thread's
|
|
13
|
+
* job, then the launcher exits. Watching the launcher pid is the liveness
|
|
14
|
+
* regression this replaces — it fired a bogus "exited" the moment the launcher
|
|
15
|
+
* died, decommissioning the still-working child. The worker is "exited" only
|
|
16
|
+
* when its JOB has drained (`/proc/alive?threadId=`), which the broker confirms
|
|
17
|
+
* by recording a terminal ledger row once no member remains.
|
|
18
|
+
*
|
|
19
|
+
* Degradation: broker unreachable → "cannot confirm → treat alive" (the
|
|
20
|
+
* audited-safe direction); the watch is kept, never resolved. A slow cold start
|
|
21
|
+
* (~50s for Copilot) keeps its launcher as a live job member, so it reports
|
|
22
|
+
* alive throughout; a first-connect grace additionally refuses to resolve an
|
|
23
|
+
* UNCONFIRMED "gone" until it elapses, so the degraded no-job path can't misfire
|
|
24
|
+
* during a slow start. A broker-CONFIRMED exit resolves immediately regardless.
|
|
25
|
+
* A watched thread is only resolved ONCE.
|
|
26
|
+
*/
|
|
27
|
+
import { log } from "../lib/logger.js";
|
|
28
|
+
import { errorMessage } from "../lib/utils.js";
|
|
29
|
+
import { brokerCheckAliveByThread } from "./broker-client.js";
|
|
30
|
+
const SWEEP_INTERVAL_MS = 20_000;
|
|
31
|
+
/** Cold start can be ~50s (Copilot); hold any UNCONFIRMED "gone" until this
|
|
32
|
+
* elapses so a slow start is never judged dead. A broker-confirmed terminal
|
|
33
|
+
* exit bypasses it — fast-exit respawn depends on prompt, accurate reporting. */
|
|
34
|
+
let firstConnectGraceMs = 90_000;
|
|
35
|
+
/** Ledger states that mean the worker is truly, confirmedly gone. NOTE:
|
|
36
|
+
* "kill-failed" is deliberately excluded — it means the kill FAILED and the
|
|
37
|
+
* process may still be ALIVE (e.g. the uncontained Avecto jobAssignFailed path).
|
|
38
|
+
* Treating it as terminal would confirm the death of a live worker and orphan it;
|
|
39
|
+
* instead it falls through to the first-connect grace path. Only a broker-recorded
|
|
40
|
+
* "exited"/"killed" is proof the worker is gone. */
|
|
41
|
+
const CONFIRMED_EXIT_STATES = new Set(["exited", "killed"]);
|
|
42
|
+
const watched = new Map();
|
|
43
|
+
let timer = null;
|
|
44
|
+
let sweepInFlight = false;
|
|
45
|
+
/** Register a broker-spawned thread for exit detection. Keyed by threadId. */
|
|
46
|
+
export function watchBrokerSpawnExit(entry) {
|
|
47
|
+
watched.set(entry.threadId, { ...entry, watchedSince: Date.now() });
|
|
48
|
+
if (timer === null) {
|
|
49
|
+
timer = setInterval(() => void sweep(), SWEEP_INTERVAL_MS);
|
|
50
|
+
timer.unref();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function sweep() {
|
|
54
|
+
if (sweepInFlight)
|
|
55
|
+
return; // a slow broker must not stack sweeps
|
|
56
|
+
sweepInFlight = true;
|
|
57
|
+
try {
|
|
58
|
+
for (const entry of [...watched.values()]) {
|
|
59
|
+
try {
|
|
60
|
+
await checkOne(entry);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
log.warn(`[exit-watch] sweep failed for thread ${entry.threadId} (pid ${entry.pid}): ${errorMessage(err)}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
sweepInFlight = false;
|
|
69
|
+
if (watched.size === 0 && timer !== null) {
|
|
70
|
+
clearInterval(timer);
|
|
71
|
+
timer = null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function checkOne(entry) {
|
|
76
|
+
const verdict = await brokerCheckAliveByThread(entry.threadId);
|
|
77
|
+
// Broker unreachable → cannot confirm the job is empty → treat as alive. A dead
|
|
78
|
+
// launcher pid is NEVER, on its own, evidence the worker died (that was the bug).
|
|
79
|
+
if (verdict === null)
|
|
80
|
+
return;
|
|
81
|
+
if (verdict.known && verdict.alive)
|
|
82
|
+
return; // job still has a live member
|
|
83
|
+
// Not alive. Resolve immediately only when the broker has CONFIRMED the worker is
|
|
84
|
+
// gone — its handle-wait recorded a terminal row once the job drained. Otherwise
|
|
85
|
+
// (a 'running'/'superseded' row still pending, an unknown thread, or the degraded
|
|
86
|
+
// no-job path) hold until the first-connect grace elapses, so a slow cold start is
|
|
87
|
+
// never mistaken for a death.
|
|
88
|
+
const confirmed = verdict.registryState != null && CONFIRMED_EXIT_STATES.has(verdict.registryState);
|
|
89
|
+
const graceElapsed = Date.now() - entry.watchedSince >= firstConnectGraceMs;
|
|
90
|
+
if (confirmed) {
|
|
91
|
+
resolveExit(entry, verdict.exitCode ?? null, verdict.registryState ?? undefined);
|
|
92
|
+
}
|
|
93
|
+
else if (graceElapsed) {
|
|
94
|
+
resolveExit(entry, verdict.exitCode ?? null, "grace-window-elapsed");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function resolveExit(entry, exitCode, source) {
|
|
98
|
+
if (!watched.delete(entry.threadId))
|
|
99
|
+
return; // already resolved
|
|
100
|
+
log.info(`[exit-watch] broker-spawned thread ${entry.threadId} (pid ${entry.pid}) exited: code ${exitCode ?? "unknown"}${source ? ` (${source})` : ""}`);
|
|
101
|
+
try {
|
|
102
|
+
entry.onExit(exitCode);
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
log.warn(`[exit-watch] onExit handler failed for thread ${entry.threadId}: ${errorMessage(err)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Test hooks. */
|
|
109
|
+
export function stopExitWatcher() {
|
|
110
|
+
if (timer !== null) {
|
|
111
|
+
clearInterval(timer);
|
|
112
|
+
timer = null;
|
|
113
|
+
}
|
|
114
|
+
watched.clear();
|
|
115
|
+
}
|
|
116
|
+
export function sweepOnceForTest() {
|
|
117
|
+
return sweep();
|
|
118
|
+
}
|
|
119
|
+
export function watchedCountForTest() {
|
|
120
|
+
return watched.size;
|
|
121
|
+
}
|
|
122
|
+
/** Shrink (or restore, with null) the first-connect grace so grace-path tests
|
|
123
|
+
* don't wait 90s. */
|
|
124
|
+
export function setExitWatchGraceForTest(ms) {
|
|
125
|
+
firstConnectGraceMs = ms ?? 90_000;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=spawn-exit-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-exit-watcher.js","sourceRoot":"","sources":["../../src/services/spawn-exit-watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,6 @@ export interface ThreadsHealthOptions {
|
|
|
32
32
|
* Hidden threads are still counted in a roll-up line, so nothing is silently
|
|
33
33
|
* dropped; pass `status: "all"` or `includeDead: true` to see them.
|
|
34
34
|
*/
|
|
35
|
-
export declare function getThreadsHealth(getMemoryDb: () => ReturnType<typeof initMemoryDb>, options?: ThreadsHealthOptions): string
|
|
35
|
+
export declare function getThreadsHealth(getMemoryDb: () => ReturnType<typeof initMemoryDb>, options?: ThreadsHealthOptions): Promise<string>;
|
|
36
36
|
export {};
|
|
37
37
|
//# sourceMappingURL=thread-health.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-health.service.d.ts","sourceRoot":"","sources":["../../src/services/thread-health.service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAS7D,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/D,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"thread-health.service.d.ts","sourceRoot":"","sources":["../../src/services/thread-health.service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAS7D,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE/D,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,OAAO,CAAC;CACpB;AA+FD,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,eAAe,GAAG,YAAY,CAarE;AAED,0FAA0F;AAC1F,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,MAAM,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC9B,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA+BD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,UAAU,CAAC,OAAO,YAAY,CAAC,EAClD,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,MAAM,CAAC,CAmEjB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getAllRegisteredTopics } from "../sessions/topic-registry.js";
|
|
2
2
|
import { getDashboardSessions, WAIT_LIVENESS_MS } from "../sessions/dashboard-registry.js";
|
|
3
3
|
import { getAllThreads } from "../data/memory/thread-registry.js";
|
|
4
|
-
import {
|
|
4
|
+
import { isThreadAlive, readPidFiles, spawnedThreads, } from "./process.service.js";
|
|
5
5
|
import { log } from "../lib/logger.js";
|
|
6
6
|
const formatRelativeTime = (ms) => ms < 0
|
|
7
7
|
? "just now"
|
|
@@ -22,7 +22,7 @@ const formatUptime = (startedAt) => {
|
|
|
22
22
|
const hours = Math.floor(minutes / 60);
|
|
23
23
|
return hours < 24 ? `${hours}h ${minutes % 60}m` : `${Math.floor(hours / 24)}d ${hours % 24}h`;
|
|
24
24
|
};
|
|
25
|
-
function collectThreadData(getMemoryDb) {
|
|
25
|
+
async function collectThreadData(getMemoryDb) {
|
|
26
26
|
const topicsByChat = getAllRegisteredTopics();
|
|
27
27
|
const sessions = getDashboardSessions();
|
|
28
28
|
const pidFiles = readPidFiles();
|
|
@@ -65,7 +65,7 @@ function collectThreadData(getMemoryDb) {
|
|
|
65
65
|
arr.push(session);
|
|
66
66
|
sessionsByThread.set(session.threadId, arr);
|
|
67
67
|
}
|
|
68
|
-
return [...allThreadIds].map((threadId) => {
|
|
68
|
+
return Promise.all([...allThreadIds].map(async (threadId) => {
|
|
69
69
|
const spawnedEntry = spawnedByThread.get(threadId);
|
|
70
70
|
const pidFileEntry = pidFileByThread.get(threadId);
|
|
71
71
|
const pid = spawnedEntry?.pid ?? pidFileEntry?.pid;
|
|
@@ -77,8 +77,12 @@ function collectThreadData(getMemoryDb) {
|
|
|
77
77
|
threadId,
|
|
78
78
|
name: threadNames.get(threadId) ?? regEntry?.name ?? "unnamed",
|
|
79
79
|
pid,
|
|
80
|
+
// THREAD-scoped so a broker-spawned worker isn't shown dead ~20s after
|
|
81
|
+
// spawn (its launcher pid exits while the forked child keeps running in the
|
|
82
|
+
// job). Only consult the broker for threads that actually have a pid, so a
|
|
83
|
+
// pid-less topic/session row costs no broker round-trip.
|
|
80
84
|
alive: pid !== undefined &&
|
|
81
|
-
|
|
85
|
+
(await isThreadAlive(threadId, pid, spawnedEntry?.startedAt ?? pidFileEntry?.startedAt)),
|
|
82
86
|
hasActiveSession: !!activeSession,
|
|
83
87
|
hasRecentWait: anySession?.lastWaitCallAt != null && now - anySession.lastWaitCallAt < WAIT_LIVENESS_MS,
|
|
84
88
|
sessionCount: threadSessions.length,
|
|
@@ -88,7 +92,7 @@ function collectThreadData(getMemoryDb) {
|
|
|
88
92
|
registryStatus: regEntry?.status,
|
|
89
93
|
keepAlive: regEntry?.keepAlive ?? false,
|
|
90
94
|
};
|
|
91
|
-
});
|
|
95
|
+
}));
|
|
92
96
|
}
|
|
93
97
|
export function classifyThreadHealth(t) {
|
|
94
98
|
if ((t.alive && t.hasActiveSession && t.hasRecentWait) || (t.hasActiveSession && t.hasRecentWait))
|
|
@@ -142,8 +146,8 @@ function resolveStatus(raw) {
|
|
|
142
146
|
* Hidden threads are still counted in a roll-up line, so nothing is silently
|
|
143
147
|
* dropped; pass `status: "all"` or `includeDead: true` to see them.
|
|
144
148
|
*/
|
|
145
|
-
export function getThreadsHealth(getMemoryDb, options = {}) {
|
|
146
|
-
const threads = collectThreadData(getMemoryDb);
|
|
149
|
+
export async function getThreadsHealth(getMemoryDb, options = {}) {
|
|
150
|
+
const threads = await collectThreadData(getMemoryDb);
|
|
147
151
|
if (threads.length === 0)
|
|
148
152
|
return "No threads found. No topics registered, no active sessions, no PID files.";
|
|
149
153
|
const now = Date.now();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-health.service.js","sourceRoot":"","sources":["../../src/services/thread-health.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,EAAE,aAAa,EAA4B,MAAM,mCAAmC,CAAC;AAE5F,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"thread-health.service.js","sourceRoot":"","sources":["../../src/services/thread-health.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { unlinkSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
2
|
import { join } from "node:path";
|
|
3
|
+
import { dataDir } from "../lib/paths.js";
|
|
4
4
|
export var ThreadState;
|
|
5
5
|
(function (ThreadState) {
|
|
6
6
|
ThreadState["Created"] = "created";
|
|
@@ -37,7 +37,7 @@ const VALID_TRANSITIONS = {
|
|
|
37
37
|
[ThreadState.Expired]: new Set([ThreadState.Archived]),
|
|
38
38
|
};
|
|
39
39
|
function cleanupThreadFiles(threadId) {
|
|
40
|
-
const base =
|
|
40
|
+
const base = dataDir();
|
|
41
41
|
for (const filePath of [
|
|
42
42
|
join(base, "heartbeats", `${threadId}`),
|
|
43
43
|
join(base, "schedules", `${threadId}.json`),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"thread-lifecycle.service.js","sourceRoot":"","sources":["../../src/services/thread-lifecycle.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"thread-lifecycle.service.js","sourceRoot":"","sources":["../../src/services/thread-lifecycle.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-cleanup.service.d.ts","sourceRoot":"","sources":["../../src/services/worker-cleanup.service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAe,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAyBzF,eAAO,MAAM,eAAe,QAGxB,CAAC;AAQL;;;qFAGqF;AACrF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;oFAGoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE;IACN,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EACD,IAAI,EAAE;IACJ,EAAE,EAAE,UAAU,CAAC,cAAc,yBAAyB,EAAE,YAAY,CAAC,CAAC;IACtE,QAAQ,EAAE;QAAE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,sBAAsB,CAAC;CACzC,GACA,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"worker-cleanup.service.d.ts","sourceRoot":"","sources":["../../src/services/worker-cleanup.service.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAe,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAyBzF,eAAO,MAAM,eAAe,QAGxB,CAAC;AAQL;;;qFAGqF;AACrF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;oFAGoF;AACpF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE;IACN,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EACD,IAAI,EAAE;IACJ,EAAE,EAAE,UAAU,CAAC,cAAc,yBAAyB,EAAE,YAAY,CAAC,CAAC;IACtE,QAAQ,EAAE;QAAE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,sBAAsB,CAAC;CACzC,GACA,OAAO,CAAC,IAAI,CAAC,CA+Ff;AAoED,eAAO,MAAM,qBAAqB,QAAiB,CAAC;AAqEpD,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,UAAU,CAAC,cAAc,yBAAyB,EAAE,YAAY,CAAC,EACrE,QAAQ,EAAE;IACR,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,WAAW,CAAC,CACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB,EACD,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,sBAAsB,EACvC,KAAK,GAAE,MAA8B,GACpC,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAkThD"}
|
|
@@ -4,7 +4,7 @@ import { archiveNotesForThread } from "../data/memory/note-archival.js";
|
|
|
4
4
|
import { closeThreadSessions } from "../sessions/mcp-registry.js";
|
|
5
5
|
import { getExplicitTelegramTopicId, updateThread } from "../data/memory/thread-registry.js";
|
|
6
6
|
import { errorMessage } from "../lib/utils.js";
|
|
7
|
-
import { spawnedThreads, readPidFiles,
|
|
7
|
+
import { spawnedThreads, readPidFiles, killThreadTree, isThreadAlive, clearTaskConsumed, deletePendingTaskMailbox, PROCESS_BASE_DIR, } from "./process.service.js";
|
|
8
8
|
import { ThreadState } from "./thread-lifecycle.service.js";
|
|
9
9
|
import { log } from "../lib/logger.js";
|
|
10
10
|
/** True when a deleteForumTopic error means the topic is already gone — which is
|
|
@@ -68,22 +68,23 @@ export async function decommissionWorker(thread, deps) {
|
|
|
68
68
|
// agent we could NOT kill (EPERM on a server's own Windows child) does NOT
|
|
69
69
|
// make a mid-task agent self-exit — it just ORPHANS it: alive, but with no
|
|
70
70
|
// MCP connection → wedged forever. So kill, then close only if confirmed dead.
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
71
|
+
// (The old kill-retry circuit breaker is gone with the taskkill machinery:
|
|
72
|
+
// a kill is now one localhost HTTP call to the broker, so re-issuing it each
|
|
73
|
+
// sweep can no longer starve anything.)
|
|
74
|
+
// Kill by THREAD, not by the recorded pid: a launcher-forked worker's pid is the
|
|
75
|
+
// already-exited launcher, and KillByPid(launcher) hits the broker's AlreadyDead
|
|
76
|
+
// fast-path without ever touching the live forked child. Routing by threadId
|
|
77
|
+
// job-kills the real agent. (No-op if already gone.)
|
|
78
|
+
await killThreadTree(thread.threadId, "decommission", thread.pid, thread.startedAt);
|
|
80
79
|
// 2. Tear down MCP transport(s) ONLY once the process is confirmed dead. A dead
|
|
81
80
|
// process's socket is already gone, so this is bookkeeping (and marks the
|
|
82
81
|
// close expected so http-server's onclose does not re-kill). If the kill
|
|
83
82
|
// EPERM-failed and the agent is still alive, LEAVE the transport OPEN so the
|
|
84
83
|
// live agent stays connected and functional instead of being orphaned — an
|
|
85
84
|
// idle unkillable worker simply stays parked in wait, which is harmless.
|
|
86
|
-
|
|
85
|
+
// THREAD-scoped liveness: gate teardown on the broker's job verdict, never on the
|
|
86
|
+
// stale launcher pid (which reads dead ~20s post-spawn and would orphan a live child).
|
|
87
|
+
const processGone = !(await isThreadAlive(thread.threadId, thread.pid, thread.startedAt));
|
|
87
88
|
if (processGone) {
|
|
88
89
|
// Process confirmed gone — drop the unkillable anchor and the breaker entry so
|
|
89
90
|
// neither outlives the thread (and a future thread reusing this id starts clean).
|
|
@@ -105,9 +106,6 @@ export async function decommissionWorker(thread, deps) {
|
|
|
105
106
|
// later sweep re-runs decommission and completes it once the process is dead
|
|
106
107
|
// (the keeper escalates a truly unkillable process in the meantime).
|
|
107
108
|
log.warn(`[decommission] Worker thread ${thread.threadId} survived kill (still alive) — aborting teardown; topic, notes, DB row and tracking preserved until the process is confirmed dead.`);
|
|
108
|
-
// Charge the breaker only for a kill this call actually issued.
|
|
109
|
-
if (thread.pid !== undefined && killIssued)
|
|
110
|
-
recordKillFailure(thread.pid, thread.threadId);
|
|
111
109
|
return;
|
|
112
110
|
}
|
|
113
111
|
// 3. Delete Telegram topic (reached only when the process is confirmed dead).
|
|
@@ -265,85 +263,13 @@ function recordFirstUnkillableAttempt(threadId, now) {
|
|
|
265
263
|
* reuses the id starts its clock fresh. */
|
|
266
264
|
function clearUnkillableAttempt(threadId) {
|
|
267
265
|
unkillableNotifiedAt.delete(threadId);
|
|
268
|
-
killBackoff.delete(threadId);
|
|
269
266
|
const store = loadUnkillableStore();
|
|
270
267
|
if (store.delete(threadId))
|
|
271
268
|
persistUnkillableStore();
|
|
272
269
|
}
|
|
273
|
-
// ── Kill-retry circuit breaker ─────────────────────────────────────────────
|
|
274
|
-
// A process that EPERMs is not going to yield to the same taskkill five minutes
|
|
275
|
-
// later, but the sweep used to re-issue it every single cycle regardless. Each
|
|
276
|
-
// attempt is a spawned taskkill plus a process-tree walk, and with a couple of
|
|
277
|
-
// wedged workers that was enough to starve the sweep itself — the scheduler went
|
|
278
|
-
// quiet for hours while the loop did nothing but re-kill the unkillable.
|
|
279
|
-
//
|
|
280
|
-
// So: try hard a few times (most wedged workers thaw and die within minutes),
|
|
281
|
-
// then back off to an occasional retry. Liveness is still checked every sweep —
|
|
282
|
-
// only the kill is throttled — so a worker that thaws and exits on its own is
|
|
283
|
-
// still reaped promptly.
|
|
284
|
-
const UNKILLABLE_MAX_FAST_ATTEMPTS = 5;
|
|
285
|
-
const UNKILLABLE_RETRY_BACKOFF_MS = 30 * 60 * 1000;
|
|
286
|
-
// An entry in real backoff is retried at least every UNKILLABLE_RETRY_BACKOFF_MS,
|
|
287
|
-
// so its lastAttemptAt is never more than ~30m stale. Anything older belongs to a
|
|
288
|
-
// thread that left by a path which never observes its death (pid file removed by
|
|
289
|
-
// hand, exit handler that skips decommission) and would otherwise sit in the map
|
|
290
|
-
// for the life of the process.
|
|
291
|
-
const KILL_BACKOFF_TTL_MS = 24 * 60 * 60 * 1000;
|
|
292
|
-
/** threadId → the pid we have been failing to kill, how many times, and when last. */
|
|
293
|
-
const killBackoff = new Map();
|
|
294
|
-
/** Drop entries no sweep has touched in a day — see {@link KILL_BACKOFF_TTL_MS}. */
|
|
295
|
-
function pruneKillBackoff(now) {
|
|
296
|
-
for (const [threadId, state] of killBackoff)
|
|
297
|
-
if (now - state.lastAttemptAt > KILL_BACKOFF_TTL_MS)
|
|
298
|
-
killBackoff.delete(threadId);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Kill a worker's process tree unless the circuit breaker says to sit this sweep
|
|
302
|
-
* out. Returns true when a kill was actually issued — the caller MUST pass that
|
|
303
|
-
* back to {@link recordKillFailure} if the process survives, and must NOT infer
|
|
304
|
-
* it from timestamps: sweeps can overlap (setInterval does not wait for the
|
|
305
|
-
* previous run), so "the recorded attempt is mine" is not something a shared
|
|
306
|
-
* clock can answer.
|
|
307
|
-
*/
|
|
308
|
-
async function killWorkerWithBackoff(pid, threadId, caller, startedAt, now) {
|
|
309
|
-
const state = killBackoff.get(threadId);
|
|
310
|
-
// The failure history belongs to a PID, not to a thread id. A thread that is
|
|
311
|
-
// torn down and respawned gets a brand-new process which has resisted nothing
|
|
312
|
-
// and deserves the full fast-attempt budget — otherwise it inherits its
|
|
313
|
-
// predecessor's 30-minute skip and lingers for no reason.
|
|
314
|
-
const staleEntry = state !== undefined && state.pid !== pid;
|
|
315
|
-
if (state !== undefined &&
|
|
316
|
-
!staleEntry &&
|
|
317
|
-
state.failures >= UNKILLABLE_MAX_FAST_ATTEMPTS &&
|
|
318
|
-
now - state.lastAttemptAt < UNKILLABLE_RETRY_BACKOFF_MS) {
|
|
319
|
-
log.debug(`[worker-cleanup] Worker pid=${pid} thread=${threadId} in kill backoff (${state.failures} failures, last attempt ${Math.round((now - state.lastAttemptAt) / 60000)}m ago) — skipping kill this sweep (caller=${caller}).`);
|
|
320
|
-
return false;
|
|
321
|
-
}
|
|
322
|
-
killBackoff.set(threadId, {
|
|
323
|
-
pid,
|
|
324
|
-
failures: staleEntry ? 0 : (state?.failures ?? 0),
|
|
325
|
-
lastAttemptAt: now,
|
|
326
|
-
});
|
|
327
|
-
await killProcessTree(pid, threadId, caller, startedAt);
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
/** Count a survived kill against the breaker. Call ONLY when a kill was issued
|
|
331
|
-
* (i.e. {@link killWorkerWithBackoff} returned true) and the pid is still alive. */
|
|
332
|
-
function recordKillFailure(pid, threadId) {
|
|
333
|
-
const state = killBackoff.get(threadId);
|
|
334
|
-
// A concurrent sweep may have re-keyed the entry onto a different pid; that
|
|
335
|
-
// process's budget is not ours to spend.
|
|
336
|
-
if (state === undefined || state.pid !== pid)
|
|
337
|
-
return;
|
|
338
|
-
state.failures += 1;
|
|
339
|
-
if (state.failures === UNKILLABLE_MAX_FAST_ATTEMPTS) {
|
|
340
|
-
log.warn(`[worker-cleanup] Worker pid=${pid} thread=${threadId} survived ${state.failures} kills — backing off to one retry per ${UNKILLABLE_RETRY_BACKOFF_MS / 60000}m so the sweep is not starved.`);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
270
|
export async function cleanupExpiredWorkers(db, telegram, chatId, threadLifecycle, ttlMs = DEFAULT_WORKER_TTL_MS) {
|
|
344
271
|
const result = { cleaned: 0, errors: [] };
|
|
345
272
|
const now = Date.now();
|
|
346
|
-
pruneKillBackoff(now);
|
|
347
273
|
for (const thread of spawnedThreads.filter((t) => t.threadType === "worker" && now - t.createdAt > ttlMs)) {
|
|
348
274
|
try {
|
|
349
275
|
// Two-phase teardown: only counts as "cleaned" once the worker is actually
|
|
@@ -388,13 +314,15 @@ export async function cleanupExpiredWorkers(db, telegram, chatId, threadLifecycl
|
|
|
388
314
|
// self-exit — it orphans it (alive, but no MCP connection → wedged). So
|
|
389
315
|
// confirm death via the kill, then tear the transport down only in the
|
|
390
316
|
// confirmed-dead branch below.
|
|
391
|
-
|
|
392
|
-
|
|
317
|
+
// Kill by THREAD (job kill of the real forked child); the recorded pid is
|
|
318
|
+
// only a degraded-path fallback when the broker is unreachable.
|
|
319
|
+
await killThreadTree(row.thread_id, "worker-cleanup-expired", killPid, killStartedAt);
|
|
393
320
|
// Invariant: a worker's topic is deleted ONLY when its process is confirmed
|
|
394
321
|
// gone. If the kill left it alive (EPERM on a wedged child), defer topic
|
|
395
322
|
// deletion to the backstop reaper below, which re-checks liveness — deleting
|
|
396
|
-
// here would orphan the topic of a still-running worker.
|
|
397
|
-
|
|
323
|
+
// here would orphan the topic of a still-running worker. Gate on the broker's
|
|
324
|
+
// thread verdict, not the launcher pid.
|
|
325
|
+
const processGone = !(await isThreadAlive(row.thread_id, killPid, killStartedAt));
|
|
398
326
|
if (processGone) {
|
|
399
327
|
// Confirmed dead — its socket is already gone, so closing the transport
|
|
400
328
|
// is bookkeeping (and marks the close expected). Safe now.
|
|
@@ -525,7 +453,9 @@ export async function cleanupExpiredWorkers(db, telegram, chatId, threadLifecycl
|
|
|
525
453
|
const runnable = row?.status === "active" && !pastTtl;
|
|
526
454
|
if (runnable)
|
|
527
455
|
continue;
|
|
528
|
-
|
|
456
|
+
// THREAD-scoped: the launcher pid reads dead while the forked child lives, so
|
|
457
|
+
// a pid-first check here would finalize (topic-delete + archive) a live worker.
|
|
458
|
+
if (!(await isThreadAlive(entry.threadId, entry.pid, entry.startedAt))) {
|
|
529
459
|
clearUnkillableAttempt(entry.threadId);
|
|
530
460
|
// Process is confirmed dead but its topic/registry can still linger (a
|
|
531
461
|
// zombie whose exit handler never ran). This is the invariant-safe point
|
|
@@ -540,16 +470,15 @@ export async function cleanupExpiredWorkers(db, telegram, chatId, threadLifecycl
|
|
|
540
470
|
// not kill does not make a mid-task agent self-exit — it ORPHANS it (alive,
|
|
541
471
|
// but with no MCP connection → wedged forever). So kill first; only once the
|
|
542
472
|
// process is confirmed dead (below) do we tear the transport down.
|
|
543
|
-
|
|
544
|
-
//
|
|
545
|
-
const killIssued = await killWorkerWithBackoff(entry.pid, entry.threadId, "worker-cleanup-reap", entry.startedAt, now);
|
|
546
|
-
// killProcessTree resolves even when the kill FAILS (e.g. EPERM on a
|
|
473
|
+
await killThreadTree(entry.threadId, "worker-cleanup-reap", entry.pid, entry.startedAt);
|
|
474
|
+
// killThreadTree resolves even when the kill FAILS (e.g. EPERM on a
|
|
547
475
|
// Windows claude.exe whose wedged bash.exe child makes taskkill /T a
|
|
548
476
|
// no-op). Re-check liveness before claiming success — otherwise we log a
|
|
549
477
|
// phantom "Reaped", drop the tracking entry, and count it as cleaned,
|
|
550
478
|
// hiding a zombie that then reappears and "reaps" forever. If it survived,
|
|
551
479
|
// surface it to the operator (rate-limited) so it gets a manual kill.
|
|
552
|
-
|
|
480
|
+
// THREAD-scoped so a live forked child (dead launcher pid) is not falsely reaped.
|
|
481
|
+
if (await isThreadAlive(entry.threadId, entry.pid, entry.startedAt)) {
|
|
553
482
|
// Still alive after an EPERM kill — LEAVE its MCP transport OPEN so the
|
|
554
483
|
// agent stays connected rather than being orphaned (closing a live agent's
|
|
555
484
|
// socket does not make it self-exit if it is mid-task). An idle unkillable
|
|
@@ -561,9 +490,6 @@ export async function cleanupExpiredWorkers(db, telegram, chatId, threadLifecycl
|
|
|
561
490
|
// worker has resisted for the full threshold do we escalate to Telegram.
|
|
562
491
|
const firstAttempt = recordFirstUnkillableAttempt(entry.threadId, now);
|
|
563
492
|
const stuckMs = now - firstAttempt;
|
|
564
|
-
// Only count a failure for a kill we actually issued.
|
|
565
|
-
if (killIssued)
|
|
566
|
-
recordKillFailure(entry.pid, entry.threadId);
|
|
567
493
|
if (stuckMs < UNKILLABLE_ALERT_THRESHOLD_MS) {
|
|
568
494
|
log.debug(`[worker-cleanup] Worker pid=${entry.pid} thread=${entry.threadId} ('${name}') survived kill — stuck ${Math.round(stuckMs / 60000)}m, below alert threshold; retrying silently.`);
|
|
569
495
|
continue;
|