Files
openclaw/vitest.system-load.ts
2026-04-04 05:50:46 +01:00

123 lines
3.3 KiB
TypeScript

import { spawnSync } from "node:child_process";
type EnvMap = Record<string, string | undefined>;
export type VitestProcessStats = {
otherVitestRootCount: number;
otherVitestWorkerCount: number;
otherVitestCpuPercent: number;
};
type PsResult = {
status: number | null;
stdout: string;
};
type DetectVitestProcessStatsOptions = {
platform?: NodeJS.Platform;
selfPid?: number;
runPs?: () => PsResult;
};
const EMPTY_VITEST_PROCESS_STATS: VitestProcessStats = {
otherVitestRootCount: 0,
otherVitestWorkerCount: 0,
otherVitestCpuPercent: 0,
};
const BOOLEAN_TRUE_VALUES = new Set(["1", "true"]);
function isExplicitlyEnabled(value: string | undefined): boolean {
const normalized = value?.trim().toLowerCase();
return normalized ? BOOLEAN_TRUE_VALUES.has(normalized) : false;
}
function isVitestWorkerArgs(args: string): boolean {
return args.includes("/vitest/dist/workers/") || args.includes("\\vitest\\dist\\workers\\");
}
function isVitestRootArgs(args: string): boolean {
return (
args.includes("node_modules/.bin/vitest") ||
/\bvitest(?:\.(?:m?js|cmd|exe))?\b/u.test(args) ||
args.includes("scripts/test-projects.mjs") ||
args.includes("scripts/run-vitest.mjs")
);
}
function normalizeCpu(rawCpu: string): number {
const parsed = Number.parseFloat(rawCpu);
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
}
export function parseVitestProcessStats(
psOutput: string,
selfPid: number = process.pid,
): VitestProcessStats {
const stats = { ...EMPTY_VITEST_PROCESS_STATS };
for (const line of psOutput.split("\n")) {
const trimmed = line.trim();
if (trimmed.length === 0) {
continue;
}
const match = /^(\d+)\s+([0-9.]+)\s+(.*)$/u.exec(trimmed);
if (!match) {
continue;
}
const [, rawPid, rawCpu, args] = match;
const pid = Number.parseInt(rawPid, 10);
if (!Number.isFinite(pid) || pid === selfPid) {
continue;
}
if (!isVitestWorkerArgs(args) && !isVitestRootArgs(args)) {
continue;
}
stats.otherVitestCpuPercent += normalizeCpu(rawCpu);
if (isVitestWorkerArgs(args)) {
stats.otherVitestWorkerCount += 1;
} else {
stats.otherVitestRootCount += 1;
}
}
stats.otherVitestCpuPercent = Number.parseFloat(stats.otherVitestCpuPercent.toFixed(1));
return stats;
}
export function detectVitestProcessStats(
env: EnvMap = process.env,
options: DetectVitestProcessStatsOptions = {},
): VitestProcessStats {
const platform = options.platform ?? process.platform;
if (platform === "win32") {
return { ...EMPTY_VITEST_PROCESS_STATS };
}
if (isExplicitlyEnabled(env.OPENCLAW_VITEST_DISABLE_SYSTEM_THROTTLE)) {
return { ...EMPTY_VITEST_PROCESS_STATS };
}
const result =
options.runPs?.() ??
spawnSync("ps", ["-xao", "pid=,pcpu=,args="], {
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
});
if (result.status === 0 && typeof result.stdout === "string" && result.stdout.length > 0) {
return parseVitestProcessStats(result.stdout, options.selfPid ?? process.pid);
}
return { ...EMPTY_VITEST_PROCESS_STATS };
}
export function shouldPrintVitestThrottle(env: EnvMap = process.env): boolean {
const normalized = env.OPENCLAW_VITEST_PRINT_SYSTEM_THROTTLE?.trim().toLowerCase();
return normalized ? BOOLEAN_TRUE_VALUES.has(normalized) : false;
}