mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
refactor(engine): type capture failures
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
import { normalizeErrorMessage } from "../../utils/errorMessage.js";
|
||||
import { CaptureFailure, classifyCaptureFailure } from "@hyperframes/engine";
|
||||
|
||||
export class CaptureStageError extends Error {
|
||||
export class CaptureStageError extends CaptureFailure {
|
||||
readonly browserConsole: string[];
|
||||
readonly cause: unknown;
|
||||
|
||||
constructor(input: { cause: unknown; browserConsole: string[] }) {
|
||||
super(normalizeErrorMessage(input.cause));
|
||||
const classified = classifyCaptureFailure(input.cause);
|
||||
super({
|
||||
kind: classified.kind,
|
||||
message: normalizeErrorMessage(input.cause),
|
||||
cause: input.cause,
|
||||
workerDiagnostics: classified.workerDiagnostics,
|
||||
});
|
||||
this.name = "CaptureStageError";
|
||||
this.cause = input.cause;
|
||||
this.browserConsole = input.browserConsole.slice();
|
||||
if (input.cause instanceof Error && input.cause.stack) {
|
||||
this.stack = input.cause.stack;
|
||||
|
||||
@@ -80,8 +80,8 @@ import {
|
||||
resolveHeadlessShellPath,
|
||||
applyConcreteGpuScreenshotClamp,
|
||||
scaleProtocolTimeoutForComposition,
|
||||
classifyCaptureFailure,
|
||||
isMemoryExhaustionError,
|
||||
isTransientBrowserError,
|
||||
isDrawElementVerificationError,
|
||||
getDrawElementVerificationDetails,
|
||||
augmentProtocolTimeoutError,
|
||||
@@ -816,12 +816,9 @@ export function resetCaptureAttemptProgress(job: { framesRendered?: number }): v
|
||||
|
||||
export function isRecoverableParallelCaptureError(error: unknown): boolean {
|
||||
const message = normalizeErrorMessage(error);
|
||||
return (
|
||||
message.includes("[Parallel] Capture failed") &&
|
||||
/Runtime\.callFunctionOn timed out|HeadlessExperimental\.beginFrame timed out|Waiting failed|timeout exceeded|timed out|Navigation timeout|Protocol error|Target closed/i.test(
|
||||
message,
|
||||
)
|
||||
);
|
||||
if (!message.includes("[Parallel] Capture failed")) return false;
|
||||
const kind = classifyCaptureFailure(error).kind;
|
||||
return kind === "transient_browser" || kind === "protocol_timeout";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -995,11 +992,12 @@ export async function executeDiskCaptureWithAdaptiveRetry(options: {
|
||||
missingRanges = remaining;
|
||||
attempt++;
|
||||
} catch (error) {
|
||||
const failure = classifyCaptureFailure(error, { signal: options.abortSignal });
|
||||
// A cancelled render tears the browser down, which surfaces as a
|
||||
// transient-looking `Target closed`. Rethrow immediately so cancellation
|
||||
// never burns a retry (or logs a misleading transient-failure warning) —
|
||||
// the caller's abort handling owns cancellation.
|
||||
if (options.abortSignal?.aborted) {
|
||||
if (failure.kind === "cancelled") {
|
||||
throw error;
|
||||
}
|
||||
const remaining = findMissingFrameRanges(
|
||||
@@ -1028,7 +1026,7 @@ export async function executeDiskCaptureWithAdaptiveRetry(options: {
|
||||
// retry for the session-init phase they share.
|
||||
if (
|
||||
options.allowRetry &&
|
||||
isTransientBrowserError(error) &&
|
||||
failure.kind === "transient_browser" &&
|
||||
transientRetriesUsed < MAX_TRANSIENT_CAPTURE_RETRIES
|
||||
) {
|
||||
transientRetriesUsed++;
|
||||
|
||||
Reference in New Issue
Block a user