fix(producer): retry probe stage on transient browser errors (#1688)

* fix(producer): retry probe stage on transient browser errors (#1687)

The distributed render plan stage crashes when headless Chrome encounters
a transient frame detachment ("Navigating frame was detached") during
browser probe, with no retry logic. The plan tarball is never uploaded,
and all downstream chunk workers fail with S3 404.

Add a retry-with-fresh-session mechanism to the probe stage:

- `isTransientBrowserError()` classifier in the engine identifies 9
  known transient Puppeteer/Chrome errors (frame detached, target closed,
  session closed, protocol error, page crashed, execution context
  destroyed, etc.).

- `runProbeStage()` wraps browser session creation + initialization in a
  retry loop (max 2 attempts). On transient error: logs structured
  diagnostics (attempt, isTransient, error message, elapsed time), closes
  the crashed session cleanly, creates a fresh browser, and retries. Non-
  transient errors throw immediately without consuming retry budget.

- 17 unit tests for the error classifier, 3 integration tests for retry
  behavior (successful retry, immediate throw on non-transient, exhaust
  retry budget on persistent transient).

Closes #1687

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review feedback — widen retry scope, deduplicate patterns

- Move createCaptureSession inside the retry try/catch so browser launch
  failures (Failed to launch the browser process, ECONNREFUSED) are also
  retried — not just initializeSession errors.
- Deduplicate transient error patterns: remove "Protocol error.*Target
  closed" (subsumed by "Target closed") and "Navigation failed because
  browser has disconnected" (subsumed by "browser has disconnected").
- Add browser launch failure patterns: "Failed to launch the browser
  process" and "ECONNREFUSED".
- Add test for createCaptureSession transient throw (browser launch retry).
- Update test mock comment to document sync requirement with engine
  pattern list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
miga-heygen
2026-06-24 00:07:14 -04:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 899b8faa12
commit 546b2d770b
5 changed files with 251 additions and 28 deletions
@@ -1932,3 +1932,25 @@ export function getCapturePerfSummary(session: CaptureSession): CapturePerfSumma
staticDedupSkipReason: session.staticDedupSkipReason,
};
}
// ── Transient browser error classification ─────────────────────────────────
// Puppeteer/Chrome can fail with transient errors that succeed on retry with a
// fresh browser session. These are infrastructure-level failures (frame
// detachment, connection drop, OOM kill, launch failure) — NOT composition bugs.
const TRANSIENT_BROWSER_ERROR_PATTERNS = [
/Navigating frame was detached/i,
/Target closed/i,
/Session closed/i,
/browser has disconnected/i,
/Page crashed/i,
/Execution context was destroyed/i,
/Cannot find context with specified id/i,
/Failed to launch the browser process/i,
/ECONNREFUSED/i,
];
export function isTransientBrowserError(error: unknown): boolean {
const message = error instanceof Error ? error.message : String(error);
return TRANSIENT_BROWSER_ERROR_PATTERNS.some((pattern) => pattern.test(message));
}