mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
fix(engine): avoid polynomial capture failure regex
This commit is contained in:
@@ -6,6 +6,7 @@ describe("classifyCaptureFailure", () => {
|
||||
["Target closed", "transient_browser"],
|
||||
["Runtime.callFunctionOn timed out after 30000ms", "protocol_timeout"],
|
||||
["Runtime.evaluate timed out", "protocol_timeout"],
|
||||
["drawElement worker encode timed out (frame 42)", "protocol_timeout"],
|
||||
["Waiting failed: 30000ms exceeded", "protocol_timeout"],
|
||||
["JavaScript heap out of memory", "memory_exhaustion"],
|
||||
["drawElement self-verify failed", "verification"],
|
||||
@@ -55,6 +56,14 @@ describe("classifyCaptureFailure", () => {
|
||||
expect(Object.isFrozen(failure.workerDiagnostics[0]?.lines)).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies repeated operation text in linear time", () => {
|
||||
const repeatedCopy = "copy".repeat(25_000);
|
||||
|
||||
expect(classifyCaptureFailure(new Error(repeatedCopy)).kind).toBe("authoring");
|
||||
expect(classifyCaptureFailure(new Error(`${repeatedCopy} failed`)).kind).toBe("io");
|
||||
expect(classifyCaptureFailure(new Error("copy\nfailed")).kind).toBe("authoring");
|
||||
});
|
||||
|
||||
it("marks structural failures fatal but leaves retryable failures non-fatal", () => {
|
||||
expect(
|
||||
isFatalCaptureFailure(new CaptureFailure({ kind: "authoring", message: "bad source" })),
|
||||
|
||||
@@ -58,6 +58,7 @@ const PROTOCOL_TIMEOUT_PATTERNS = [
|
||||
/Runtime\.callFunctionOn timed out/i,
|
||||
/Runtime\.evaluate timed out/i,
|
||||
/HeadlessExperimental\.beginFrame timed out/i,
|
||||
/drawElement worker encode timed out \(frame \d+\)/i,
|
||||
/Protocol error[\s\S]*tim(?:ed|e) out/i,
|
||||
/Waiting failed:\s*\d+\s*ms exceeded/i,
|
||||
/Waiting failed[\s\S]*timeout/i,
|
||||
@@ -103,11 +104,25 @@ function matchesAny(message: string, patterns: readonly RegExp[]): boolean {
|
||||
return patterns.some((pattern) => pattern.test(message));
|
||||
}
|
||||
|
||||
const IO_OPERATION_TOKENS = ["read", "write", "rename", "copy", "open", "file", "directory"];
|
||||
|
||||
function hasIoOperationFailure(message: string): boolean {
|
||||
const normalized = message.toLowerCase();
|
||||
return normalized.split(/[\r\n]/).some((line) =>
|
||||
IO_OPERATION_TOKENS.some((operation) => {
|
||||
const operationIndex = line.indexOf(operation);
|
||||
if (operationIndex < 0) return false;
|
||||
const failureStart = operationIndex + operation.length;
|
||||
return line.indexOf("failed", failureStart) >= 0 || line.indexOf("error", failureStart) >= 0;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function ioError(error: unknown, message: string): boolean {
|
||||
const code = error instanceof Error ? (error as NodeJS.ErrnoException).code : undefined;
|
||||
return (
|
||||
Boolean(code && /^(?:EACCES|EEXIST|EIO|EMFILE|ENFILE|ENOENT|ENOSPC|EPERM|EROFS)$/.test(code)) ||
|
||||
/(?:read|write|rename|copy|open|file|directory).*(?:failed|error)/i.test(message)
|
||||
hasIoOperationFailure(message)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1513,6 +1513,13 @@ describe("adaptive missing-frame retry helpers", () => {
|
||||
new Error("[Parallel] Capture failed: Worker 1: HeadlessExperimental.beginFrame timed out"),
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
isRecoverableParallelCaptureError(
|
||||
new Error(
|
||||
"[Parallel] Capture failed: Worker 0: drawElement worker encode timed out (frame 42)",
|
||||
),
|
||||
),
|
||||
).toBe(true);
|
||||
expect(isRecoverableParallelCaptureError(new Error("Encoding failed: ffmpeg exited"))).toBe(
|
||||
false,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user