fix: finalize durable Pi lifecycle

This commit is contained in:
2026-08-04 21:34:08 +02:00
parent 5ba2821a1b
commit a368889838
20 changed files with 1016 additions and 147 deletions
+52 -15
View File
@@ -10,17 +10,25 @@ import {
} from "node:fs";
import { dirname } from "node:path";
export interface MaintenanceDurability {
syncDirectory(directory: string): void;
}
/** A durable admission barrier. A lease spans the complete create/resume decision. */
export class MaintenanceBarrier {
private active: boolean;
private admissions = 0;
private waiters: (() => void)[] = [];
constructor(private readonly markerFile?: string) {
constructor(
private readonly markerFile?: string,
private readonly durability: MaintenanceDurability = defaultDurability,
) {
this.active = markerFile === undefined ? false : existsSync(markerFile);
}
acquire(): (() => void) | undefined {
this.reconcileActive();
if (this.active) return undefined;
this.admissions += 1;
let released = false;
@@ -33,17 +41,44 @@ export class MaintenanceBarrier {
}
async activate(): Promise<void> {
this.persistMarker();
this.active = true;
if (this.admissions === 0) return;
await new Promise<void>((resolve) => this.waiters.push(resolve));
let persistError: unknown;
if (this.markerFile === undefined) {
this.active = true;
} else {
try {
this.persistMarker();
} catch (error) {
persistError = error;
} finally {
this.reconcileActive();
}
}
if (!this.active) throw persistError;
if (this.admissions > 0) {
await new Promise<void>((resolve) => this.waiters.push(resolve));
}
if (persistError !== undefined) throw persistError;
}
deactivate(): void {
this.removeMarker();
this.active = false;
if (this.markerFile === undefined) {
this.active = false;
return;
}
try {
this.removeMarker();
} finally {
this.reconcileActive();
}
}
status(): { active: boolean; admissions: number } {
this.reconcileActive();
return { active: this.active, admissions: this.admissions };
}
private reconcileActive(): void {
if (this.markerFile !== undefined) this.active = existsSync(this.markerFile);
}
status(): { active: boolean; admissions: number } { return { active: this.active, admissions: this.admissions }; }
private persistMarker(): void {
if (!this.markerFile) return;
@@ -59,7 +94,7 @@ export class MaintenanceBarrier {
}
try {
renameSync(temporary, this.markerFile);
syncDirectory(directory);
this.durability.syncDirectory(directory);
} catch (error) {
try { unlinkSync(temporary); } catch { /* already renamed or best-effort cleanup */ }
throw error;
@@ -69,12 +104,14 @@ export class MaintenanceBarrier {
private removeMarker(): void {
if (!this.markerFile || !existsSync(this.markerFile)) return;
unlinkSync(this.markerFile);
syncDirectory(dirname(this.markerFile));
this.durability.syncDirectory(dirname(this.markerFile));
}
}
function syncDirectory(directory: string): void {
if (process.platform === "win32") return;
const fd = openSync(directory, "r");
try { fsyncSync(fd); } finally { closeSync(fd); }
}
const defaultDurability: MaintenanceDurability = {
syncDirectory(directory: string): void {
if (process.platform === "win32") return;
const fd = openSync(directory, "r");
try { fsyncSync(fd); } finally { closeSync(fd); }
},
};