refactor(shared): reuse isPidAlive

This commit is contained in:
Peter Steinberger
2026-02-15 19:06:47 +00:00
parent c682634188
commit 5248b759fe
4 changed files with 17 additions and 39 deletions

View File

@@ -1,6 +1,7 @@
import fsSync from "node:fs";
import fs from "node:fs/promises";
import path from "node:path";
import { isPidAlive } from "../shared/pid-alive.js";
type LockFilePayload = {
pid: number;
@@ -48,18 +49,6 @@ function resolveCleanupState(): CleanupState {
return proc[CLEANUP_STATE_KEY];
}
function isAlive(pid: number): boolean {
if (!Number.isFinite(pid) || pid <= 0) {
return false;
}
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
/**
* Synchronously release all held locks.
* Used during process exit when async operations aren't reliable.
@@ -206,7 +195,7 @@ export async function acquireSessionWriteLock(params: {
const payload = await readLockPayload(lockPath);
const createdAt = payload?.createdAt ? Date.parse(payload.createdAt) : NaN;
const stale = !Number.isFinite(createdAt) || Date.now() - createdAt > staleMs;
const alive = payload?.pid ? isAlive(payload.pid) : false;
const alive = payload?.pid ? isPidAlive(payload.pid) : false;
if (stale || !alive) {
await fs.rm(lockPath, { force: true });
continue;

View File

@@ -3,6 +3,7 @@ import fsSync from "node:fs";
import fs from "node:fs/promises";
import path from "node:path";
import { resolveConfigPath, resolveGatewayLockDir, resolveStateDir } from "../config/paths.js";
import { isPidAlive } from "../shared/pid-alive.js";
const DEFAULT_TIMEOUT_MS = 5000;
const DEFAULT_POLL_INTERVAL_MS = 100;
@@ -42,18 +43,6 @@ export class GatewayLockError extends Error {
type LockOwnerStatus = "alive" | "dead" | "unknown";
function isAlive(pid: number): boolean {
if (!Number.isFinite(pid) || pid <= 0) {
return false;
}
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
function normalizeProcArg(arg: string): string {
return arg.replaceAll("\\", "/").toLowerCase();
}
@@ -116,7 +105,7 @@ function resolveGatewayOwnerStatus(
payload: LockPayload | null,
platform: NodeJS.Platform,
): LockOwnerStatus {
if (!isAlive(pid)) {
if (!isPidAlive(pid)) {
return "dead";
}
if (platform !== "linux") {

View File

@@ -1,5 +1,6 @@
import fs from "node:fs/promises";
import path from "node:path";
import { isPidAlive } from "../shared/pid-alive.js";
export type FileLockOptions = {
retries: {
@@ -37,18 +38,6 @@ function resolveHeldLocks(): Map<string, HeldLock> {
const HELD_LOCKS = resolveHeldLocks();
function isAlive(pid: number): boolean {
if (!Number.isFinite(pid) || pid <= 0) {
return false;
}
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
function computeDelayMs(retries: FileLockOptions["retries"], attempt: number): number {
const base = Math.min(
retries.maxTimeout,
@@ -85,7 +74,7 @@ async function resolveNormalizedFilePath(filePath: string): Promise<string> {
async function isStaleLock(lockPath: string, staleMs: number): Promise<boolean> {
const payload = await readLockPayload(lockPath);
if (payload?.pid && !isAlive(payload.pid)) {
if (payload?.pid && !isPidAlive(payload.pid)) {
return true;
}
if (payload?.createdAt) {

11
src/shared/pid-alive.ts Normal file
View File

@@ -0,0 +1,11 @@
export function isPidAlive(pid: number): boolean {
if (!Number.isFinite(pid) || pid <= 0) {
return false;
}
try {
process.kill(pid, 0);
return true;
} catch {
return false;
}
}