66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
import { dirname } from 'node:path';
|
|
|
|
export const GPU_CRASH_WINDOW_MS = 10 * 60 * 1000;
|
|
export const GPU_CRASH_THRESHOLD = 2;
|
|
|
|
export type GpuFallbackState = {
|
|
crashCount: number;
|
|
lastCrashAt: number;
|
|
reason: string;
|
|
};
|
|
|
|
function isState(value: unknown): value is GpuFallbackState {
|
|
if (!value || typeof value !== 'object') return false;
|
|
const record = value as Record<string, unknown>;
|
|
return Number.isFinite(record.crashCount)
|
|
&& Number.isFinite(record.lastCrashAt)
|
|
&& typeof record.reason === 'string';
|
|
}
|
|
|
|
export function readGpuFallbackState(
|
|
filePath: string,
|
|
now = Date.now(),
|
|
): GpuFallbackState | null {
|
|
try {
|
|
const parsed: unknown = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
if (!isState(parsed)) return null;
|
|
if (now - parsed.lastCrashAt > GPU_CRASH_WINDOW_MS) return null;
|
|
return parsed;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function shouldUseSoftwareRendering(input: {
|
|
envDisabled?: boolean;
|
|
cliDisabled?: boolean;
|
|
state?: GpuFallbackState | null;
|
|
now?: number;
|
|
}): boolean {
|
|
if (input.envDisabled || input.cliDisabled) return true;
|
|
const state = input.state;
|
|
if (!state) return false;
|
|
const now = input.now ?? Date.now();
|
|
return now - state.lastCrashAt <= GPU_CRASH_WINDOW_MS
|
|
&& state.crashCount >= GPU_CRASH_THRESHOLD;
|
|
}
|
|
|
|
export function recordGpuCrash(
|
|
filePath: string,
|
|
reason: string,
|
|
now = Date.now(),
|
|
): GpuFallbackState {
|
|
const previous = readGpuFallbackState(filePath, now);
|
|
const next: GpuFallbackState = {
|
|
crashCount: previous ? previous.crashCount + 1 : 1,
|
|
lastCrashAt: now,
|
|
reason,
|
|
};
|
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
const temporaryPath = `${filePath}.${process.pid}.tmp`;
|
|
writeFileSync(temporaryPath, `${JSON.stringify(next)}\n`, 'utf8');
|
|
renameSync(temporaryPath, filePath);
|
|
return next;
|
|
}
|