fix: record Linux process birth from kernel ticks

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-06 13:52:35 -05:00
1 parent d26ff52272
commit 9fdcefcc34
10 files changed
+149 -22

No files matched your search

+9 -7
View File
@@ -89,18 +89,20 @@ describe("hot-restart path compatibility", () => {
).not.toBeNull();
});
it("reads Linux process start time from proc metadata", async () => {
it("reads Linux process birth from kernel ticks rather than proc directory metadata", async () => {
await expect(
readProcessStartedAt(123, {
platform: "linux",
stat: async (target) => {
expect(target).toBe("/proc/123");
return {
ctimeMs: Date.parse("2026-08-01T01:00:00.123Z"),
};
linuxProcessStart: {
clockTicksPerSecond: 100,
readFile: (target) => target === "/proc/stat"
? `btime ${Date.parse("2026-08-01T01:00:00.000Z") / 1000}\n`
: target === "/proc/123/stat"
? `123 (runner) S ${Array(18).fill("0").join(" ")} 123\n`
: (() => { throw new Error("Unexpected proc read"); })(),
},
}),
).resolves.toBe("2026-08-01T01:00:00.123Z");
).resolves.toBe("2026-08-01T01:00:01.230Z");
});
it("reads macOS process start time through ps", async () => {
+3 -5
View File
@@ -1,6 +1,7 @@
import { execFile } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
import { readLinuxProcessStartedAt, type LinuxProcessStartOptions } from "@paperclipai/paperclip-runner";
import {
resolvePaperclipHomeDir,
resolvePaperclipInstanceId,
@@ -14,7 +15,6 @@ const HOT_RESTART_LOCK_STALE_MS = 30_000;
const HOT_RESTART_LOCK_TIMEOUT_MS = 10_000;
type ProcessCommandRunner = (command: string, args: string[]) => Promise<string>;
type ProcessStatReader = (target: string) => Promise<{ ctimeMs: number }>;
export type HotRestartIntentRun = {
runId: string;
@@ -178,17 +178,15 @@ export async function readProcessStartedAt(
pid: number,
options: {
platform?: NodeJS.Platform;
stat?: ProcessStatReader;
linuxProcessStart?: LinuxProcessStartOptions;
runCommand?: ProcessCommandRunner;
} = {},
) {
const platform = options.platform ?? process.platform;
const stat = options.stat ?? fs.stat;
const runCommand = options.runCommand ?? runProcessCommand;
if (platform === "linux") {
const processStat = await stat(`/proc/${pid}`);
return new Date(processStat.ctimeMs).toISOString();
return readLinuxProcessStartedAt(pid, options.linuxProcessStart);
}
if (["darwin", "freebsd", "openbsd", "aix", "sunos"].includes(platform)) {