openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
80 lines (79 loc) • 4.41 kB
JavaScript
import { t as sanitizeForLog } from "./ansi-DrXAcdMD.js";
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { r as truncateUtf16Safe } from "./utf16-slice-D_ngcYKd.js";
//#region src/daemon/service-runtime.ts
/** Shared daemon runtime status types and systemd cgroup hygiene helpers. */
const SERVICE_RUNTIME_INSPECTION_ERROR_MAX_CHARS = 500;
const SERVICE_RUNTIME_INSPECTION_FAILED_DETAIL = "service runtime inspection failed";
/** Keeps native probe failures bounded and diagnostic-only for status presentation owners. */
function createServiceRuntimeInspectionFailure(error) {
const rawDetail = error instanceof Error ? error.message : String(error);
return {
status: "unknown",
detail: SERVICE_RUNTIME_INSPECTION_FAILED_DETAIL,
inspectionFailure: {
code: "service-runtime-inspection-failed",
detail: truncateUtf16Safe(sanitizeForLog(rawDetail), SERVICE_RUNTIME_INSPECTION_ERROR_MAX_CHARS) || "unknown error"
}
};
}
const SYSTEMD_TASKS_CURRENT_WARNING_THRESHOLD = 200;
const SYSTEMD_MEMORY_CURRENT_WARNING_BYTES = 2147483648;
const SYSTEMD_NO_RESTART_EXIT_STATUS = 78;
function isRiskySystemdKillMode(value) {
const normalized = normalizeLowercaseStringOrEmpty(value);
return normalized === "process" || normalized === "none";
}
function formatBytesAsGiB(value) {
const gib = value / 1024 / 1024 / 1024;
const formatted = gib >= 1 ? gib.toFixed(1).replace(/\.0$/, "") : `${value}B`;
return gib >= 1 ? `${formatted}GiB` : formatted;
}
function describeSystemdCgroupLoadWarnings(runtime) {
if (!runtime) return [];
const killMode = runtime?.killMode;
if (!isRiskySystemdKillMode(killMode)) return [];
const details = [];
if (runtime.tasksCurrent !== void 0 && Number.isSafeInteger(runtime.tasksCurrent) && runtime.tasksCurrent >= SYSTEMD_TASKS_CURRENT_WARNING_THRESHOLD) details.push(`tasks=${runtime.tasksCurrent}`);
if (runtime.memoryCurrent !== void 0 && Number.isSafeInteger(runtime.memoryCurrent) && runtime.memoryCurrent >= SYSTEMD_MEMORY_CURRENT_WARNING_BYTES) details.push(`memory=${formatBytesAsGiB(runtime.memoryCurrent)}`);
return details;
}
function getSystemdCgroupHygieneSummary(runtime) {
if (!runtime || !runtime.killMode) return null;
const details = describeSystemdCgroupLoadWarnings(runtime);
if (details.length === 0) return null;
return `cgroup hygiene: KillMode=${runtime.killMode}, ${details.join(", ")}`;
}
function isSystemdCgroupHygieneRisk(runtime) {
return getSystemdCgroupHygieneSummary(runtime) !== null;
}
/**
* True when systemd has stopped auto-restarting the gateway because it crashed
* faster than StartLimitBurst/StartLimitIntervalSec allows. Unlike an ordinary
* stopped/exited unit, this terminal latch needs an explicit `reset-failed` +
* restart to recover, so status/doctor must surface it instead of the generic
* "exited immediately" message.
*
* Detection: the unit is `failed` and either systemd reported the give-up
* directly (Result=start-limit-hit, the start-was-refused-before-exec case) or
* the restart counter reached the configured burst. The counter path is the
* common one: once the gateway process has actually run and exited non-zero,
* systemd keeps Result=exit-code and never overwrites it with start-limit-hit
* (verified against systemd 249), so Result alone misses real crash loops.
*
* The counter path is guarded against the deliberate no-restart exit: a last
* exit of 78 (EX_CONFIG, held back by RestartPreventExitStatus=78) means
* systemd stopped on purpose, so a stale NRestarts left over from earlier
* crashes must not be mistaken for start-limit exhaustion. The explicit
* Result=start-limit-hit signal stays authoritative regardless of exit status.
*/
function isSystemdStartLimitHit(runtime) {
if (!runtime || normalizeLowercaseStringOrEmpty(runtime.state) !== "failed") return false;
const systemd = runtime.systemd;
if (!systemd) return false;
if (normalizeLowercaseStringOrEmpty(systemd.result) === "start-limit-hit") return true;
if (runtime.lastExitStatus === SYSTEMD_NO_RESTART_EXIT_STATUS) return false;
return typeof systemd.startLimitBurst === "number" && systemd.startLimitBurst > 0 && typeof systemd.nRestarts === "number" && systemd.nRestarts >= systemd.startLimitBurst;
}
//#endregion
export { isSystemdStartLimitHit as i, getSystemdCgroupHygieneSummary as n, isSystemdCgroupHygieneRisk as r, createServiceRuntimeInspectionFailure as t };