mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-20 21:23:23 +00:00
ci: fix additional guard failures
This commit is contained in:
@@ -12,6 +12,8 @@ import { resolveBuildRequirement } from "./run-node.mjs";
|
||||
const DEFAULTS = {
|
||||
outputDir: path.join(process.cwd(), ".local", "gateway-watch-regression"),
|
||||
windowMs: 10_000,
|
||||
readyTimeoutMs: 20_000,
|
||||
readySettleMs: 500,
|
||||
sigkillGraceMs: 10_000,
|
||||
cpuWarnMs: 1_000,
|
||||
cpuFailMs: 8_000,
|
||||
@@ -51,6 +53,12 @@ function parseArgs(argv) {
|
||||
case "--window-ms":
|
||||
options.windowMs = Number(readValue());
|
||||
break;
|
||||
case "--ready-timeout-ms":
|
||||
options.readyTimeoutMs = Number(readValue());
|
||||
break;
|
||||
case "--ready-settle-ms":
|
||||
options.readySettleMs = Number(readValue());
|
||||
break;
|
||||
case "--sigkill-grace-ms":
|
||||
options.sigkillGraceMs = Number(readValue());
|
||||
break;
|
||||
@@ -229,6 +237,90 @@ function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function parsePsCpuTimeMs(timeText) {
|
||||
const [maybeDays, clockText] = timeText.includes("-") ? timeText.split("-", 2) : ["0", timeText];
|
||||
const days = Number(maybeDays);
|
||||
const parts = clockText.split(":");
|
||||
if (!Number.isFinite(days) || parts.length < 2 || parts.length > 3) {
|
||||
return null;
|
||||
}
|
||||
const seconds = Number(parts.at(-1));
|
||||
const minutes = Number(parts.at(-2));
|
||||
const hours = parts.length === 3 ? Number(parts[0]) : 0;
|
||||
if (![seconds, minutes, hours].every(Number.isFinite)) {
|
||||
return null;
|
||||
}
|
||||
return Math.round(((days * 24 + hours) * 60 * 60 + minutes * 60 + seconds) * 1000);
|
||||
}
|
||||
|
||||
function readProcessTreeCpuMs(rootPid) {
|
||||
if (!Number.isInteger(rootPid) || rootPid <= 0) {
|
||||
return null;
|
||||
}
|
||||
const result = spawnSync("ps", ["-eo", "pid=,ppid=,time="], {
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
});
|
||||
if (result.status !== 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
for (const line of result.stdout.split("\n")) {
|
||||
const match = line.trim().match(/^(\d+)\s+(\d+)\s+(\S+)$/);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
const pid = Number(match[1]);
|
||||
const ppid = Number(match[2]);
|
||||
const cpuMs = parsePsCpuTimeMs(match[3]);
|
||||
if (!Number.isInteger(pid) || !Number.isInteger(ppid) || cpuMs == null) {
|
||||
continue;
|
||||
}
|
||||
rows.push({ pid, ppid, cpuMs });
|
||||
}
|
||||
|
||||
const childrenByParent = new Map();
|
||||
const cpuByPid = new Map();
|
||||
for (const row of rows) {
|
||||
cpuByPid.set(row.pid, row.cpuMs);
|
||||
const children = childrenByParent.get(row.ppid) ?? [];
|
||||
children.push(row.pid);
|
||||
childrenByParent.set(row.ppid, children);
|
||||
}
|
||||
if (!cpuByPid.has(rootPid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let totalCpuMs = 0;
|
||||
const seen = new Set();
|
||||
const stack = [rootPid];
|
||||
while (stack.length > 0) {
|
||||
const pid = stack.pop();
|
||||
if (!pid || seen.has(pid)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(pid);
|
||||
totalCpuMs += cpuByPid.get(pid) ?? 0;
|
||||
for (const childPid of childrenByParent.get(pid) ?? []) {
|
||||
stack.push(childPid);
|
||||
}
|
||||
}
|
||||
return totalCpuMs;
|
||||
}
|
||||
|
||||
async function waitForGatewayReady(readText, timeoutMs) {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
while (Date.now() < deadline) {
|
||||
if (/\[gateway\] ready \(/.test(readText())) {
|
||||
return true;
|
||||
}
|
||||
await sleep(100);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function allocateLoopbackPort() {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const server = net.createServer();
|
||||
@@ -355,7 +447,16 @@ async function runTimedWatch(options, outputDir) {
|
||||
await sleep(100);
|
||||
}
|
||||
|
||||
const readyBeforeWindow = await waitForGatewayReady(
|
||||
() => `${stdout}\n${stderr}`,
|
||||
options.readyTimeoutMs,
|
||||
);
|
||||
if (readyBeforeWindow && options.readySettleMs > 0) {
|
||||
await sleep(options.readySettleMs);
|
||||
}
|
||||
const idleCpuStartMs = watchPid ? readProcessTreeCpuMs(watchPid) : null;
|
||||
await sleep(options.windowMs);
|
||||
const idleCpuEndMs = watchPid ? readProcessTreeCpuMs(watchPid) : null;
|
||||
|
||||
if (watchPid) {
|
||||
try {
|
||||
@@ -390,6 +491,11 @@ async function runTimedWatch(options, outputDir) {
|
||||
return {
|
||||
exit,
|
||||
timing,
|
||||
readyBeforeWindow,
|
||||
idleCpuMs:
|
||||
idleCpuStartMs == null || idleCpuEndMs == null
|
||||
? null
|
||||
: Math.max(0, idleCpuEndMs - idleCpuStartMs),
|
||||
stdoutPath,
|
||||
stderrPath,
|
||||
timeFilePath,
|
||||
@@ -503,7 +609,10 @@ async function main() {
|
||||
const distRuntimeAddedPaths = diff.added.filter((entry) =>
|
||||
entry.startsWith("dist-runtime/"),
|
||||
).length;
|
||||
const cpuMs = Math.round((watchResult.timing.userSeconds + watchResult.timing.sysSeconds) * 1000);
|
||||
const totalCpuMs = Math.round(
|
||||
(watchResult.timing.userSeconds + watchResult.timing.sysSeconds) * 1000,
|
||||
);
|
||||
const cpuMs = watchResult.idleCpuMs ?? totalCpuMs;
|
||||
const watchTriggeredBuild =
|
||||
fs
|
||||
.readFileSync(watchResult.stderrPath, "utf8")
|
||||
@@ -519,6 +628,8 @@ async function main() {
|
||||
watchTriggeredBuild,
|
||||
watchBuildReason,
|
||||
cpuMs,
|
||||
totalCpuMs,
|
||||
readyBeforeWindow: watchResult.readyBeforeWindow,
|
||||
cpuWarnMs: options.cpuWarnMs,
|
||||
cpuFailMs: options.cpuFailMs,
|
||||
distRuntimeFileGrowth,
|
||||
|
||||
Reference in New Issue
Block a user