Protect active development Graphs from rejected launcher cleanup
This commit is contained in:
@@ -1,14 +1,19 @@
|
|||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
|
|
||||||
|
export class FileLockBusyError extends Error {}
|
||||||
|
|
||||||
/** Kernel-owned lock: a crashed coordinator cannot leave a stale ownership file.
|
/** Kernel-owned lock: a crashed coordinator cannot leave a stale ownership file.
|
||||||
* The persistent file is just an inode; EOF releases the helper's lock. */
|
* The persistent file is just an inode; EOF releases the helper's lock. */
|
||||||
export async function withFileLock<T>(filename: string, work: () => Promise<T>): Promise<T> {
|
export async function withFileLock<T>(
|
||||||
|
filename: string,
|
||||||
|
work: () => Promise<T>,
|
||||||
|
{ nonblocking = false }: { nonblocking?: boolean } = {},
|
||||||
|
): Promise<T> {
|
||||||
const child = spawn(
|
const child = spawn(
|
||||||
"flock",
|
"flock",
|
||||||
[
|
[
|
||||||
"--exclusive",
|
"--exclusive",
|
||||||
"--timeout",
|
...(nonblocking ? ["--nonblock"] : ["--timeout", "120"]),
|
||||||
"120",
|
|
||||||
"--conflict-exit-code",
|
"--conflict-exit-code",
|
||||||
"75",
|
"75",
|
||||||
filename,
|
filename,
|
||||||
@@ -32,15 +37,17 @@ export async function withFileLock<T>(filename: string, work: () => Promise<T>):
|
|||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
let output = "";
|
let output = "";
|
||||||
child.once("error", reject);
|
child.once("error", reject);
|
||||||
child.once("exit", (code) =>
|
child.once("exit", (code) => {
|
||||||
reject(
|
reject(
|
||||||
new Error(
|
code === 75
|
||||||
code === 75
|
? new FileLockBusyError(
|
||||||
? "Timed out after 120 seconds waiting for another authoring command; inspect that command before retrying"
|
nonblocking
|
||||||
: `Cannot acquire authoring lock: ${diagnostics}`,
|
? "Another process owns this lock"
|
||||||
),
|
: "Timed out after 120 seconds waiting for another authoring command; inspect that command before retrying",
|
||||||
),
|
)
|
||||||
);
|
: new Error(`Cannot acquire authoring lock: ${diagnostics}`),
|
||||||
|
);
|
||||||
|
});
|
||||||
child.stdout.on("data", (chunk) => {
|
child.stdout.on("data", (chunk) => {
|
||||||
output += chunk;
|
output += chunk;
|
||||||
if (output.includes("locked\n")) resolve();
|
if (output.includes("locked\n")) resolve();
|
||||||
|
|||||||
Reference in New Issue
Block a user