





















@@ -0,0 +1,96 @@
1+import { createSubsystemLogger } from "../../logging/subsystem.js";
2+3+export const QA_PARENT_PID_ENV = "OPENCLAW_QA_PARENT_PID";
4+5+const DEFAULT_QA_PARENT_WATCHDOG_INTERVAL_MS = 1000;
6+7+type QaParentWatchdogTimer =
8+| number
9+| {
10+unref?: () => unknown;
11+};
12+13+type QaParentWatchdogDeps = {
14+clearInterval?: (timer: QaParentWatchdogTimer) => void;
15+env?: NodeJS.ProcessEnv;
16+exit?: (code?: number) => never | void;
17+intervalMs?: number;
18+kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
19+logger?: Pick<ReturnType<typeof createSubsystemLogger>, "warn">;
20+ownPid?: number;
21+setInterval?: (callback: () => void, ms: number) => QaParentWatchdogTimer;
22+};
23+24+export type QaParentWatchdogHandle = {
25+parentPid: number;
26+stop: () => void;
27+};
28+29+function resolveQaParentPid(env: NodeJS.ProcessEnv, ownPid: number): number | null {
30+const raw = env[QA_PARENT_PID_ENV]?.trim();
31+if (!raw) {
32+return null;
33+}
34+const parentPid = Number(raw);
35+if (!Number.isSafeInteger(parentPid) || parentPid <= 0 || parentPid === ownPid) {
36+return null;
37+}
38+return parentPid;
39+}
40+41+export function installQaParentWatchdog(
42+deps: QaParentWatchdogDeps = {},
43+): QaParentWatchdogHandle | null {
44+const env = deps.env ?? process.env;
45+const ownPid = deps.ownPid ?? process.pid;
46+const parentPid = resolveQaParentPid(env, ownPid);
47+if (parentPid === null) {
48+return null;
49+}
50+51+const clearIntervalFn =
52+deps.clearInterval ??
53+((activeTimer: QaParentWatchdogTimer) => {
54+clearInterval(activeTimer as ReturnType<typeof setInterval>);
55+});
56+const exit = deps.exit ?? ((code?: number) => process.exit(code));
57+const kill =
58+deps.kill ?? ((pid: number, signal?: NodeJS.Signals | 0) => process.kill(pid, signal));
59+const logger = deps.logger ?? createSubsystemLogger("gateway");
60+const setIntervalFn =
61+deps.setInterval ??
62+((callback: () => void, ms: number) => setInterval(callback, ms) as QaParentWatchdogTimer);
63+let stopped = false;
64+let timer: QaParentWatchdogTimer;
65+66+const stop = () => {
67+if (stopped) {
68+return;
69+}
70+stopped = true;
71+clearIntervalFn(timer);
72+};
73+74+timer = setIntervalFn(() => {
75+if (stopped) {
76+return;
77+}
78+try {
79+kill(parentPid, 0);
80+} catch (error) {
81+if ((error as NodeJS.ErrnoException).code === "ESRCH") {
82+logger.warn(`QA gateway parent pid ${parentPid} exited; shutting down orphaned QA gateway`);
83+stop();
84+exit(0);
85+}
86+}
87+}, deps.intervalMs ?? DEFAULT_QA_PARENT_WATCHDOG_INTERVAL_MS);
88+if (typeof timer === "object") {
89+timer.unref?.();
90+}
91+92+return {
93+ parentPid,
94+ stop,
95+};
96+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。