mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 23:03:09 +00:00
fix(engine): recognize Bun/JavaScriptCore's OOM message in isMemoryExhaustionError
Found while testing the previous commit's OOM-drops-to-1-worker fallback end-to-end: the producer's deployed runtime is Bun (JavaScriptCore), not Node (V8) — see packages/gcp-cloud-run/Dockerfile's `bun dist/server.js` entrypoint. All 7 MEMORY_EXHAUSTION_ERROR_PATTERNS are V8-specific allocation failure signatures; JSC's equivalent for the same single-oversized-allocation RangeErrors is the bare string "Out of memory" (verified against real Bun behavior), which none of them match. Without this, isMemoryExhaustionError returns false for genuine production OOM, so the memory-specific worker-count reduction just added would never actually engage where it's deployed — every OOM would fall through to the generic capture_error retry path instead. Matches the FULL (trimmed) message only, not merely a substring — same rationale as the existing V8 patterns' comment: "out of memory" also appears in benign WebGL/GPU console noise that must not trip this classifier. Verified end-to-end from a script inside the producer workspace (importing the real @hyperframes/engine source, not a stale globally-cached npm dist a script outside the workspace would otherwise resolve to): a genuine Bun RangeError from new Uint8Array(Number.MAX_SAFE_INTEGER) now correctly classifies as memory exhaustion and drives both resolveInversionRetryPlan and resolveParallelRouterRetryPlan down to workerCount=1 on retry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
51353a7ed6
commit
b3f244a7e9
@@ -88,4 +88,25 @@ describe("isMemoryExhaustionError", () => {
|
||||
expect(isTransientBrowserError(new Error("Set maximum size exceeded"))).toBe(false);
|
||||
expect(isMemoryExhaustionError(new Error("Target closed"))).toBe(false);
|
||||
});
|
||||
|
||||
// The producer's deployed runtime is Bun (JavaScriptCore), not Node (V8) —
|
||||
// none of the V8-specific patterns above match JSC's allocation-failure
|
||||
// message. Verified against real Bun behavior: `new
|
||||
// Uint8Array(Number.MAX_SAFE_INTEGER)`, an unbounded `Set`, and
|
||||
// `"x".repeat(2**53)` all throw exactly "Out of memory" under `bun run`.
|
||||
it("recognizes Bun/JavaScriptCore's exact OOM message", () => {
|
||||
expect(isMemoryExhaustionError(new Error("Out of memory"))).toBe(true);
|
||||
expect(isMemoryExhaustionError(new Error("out of memory"))).toBe(true);
|
||||
expect(isMemoryExhaustionError(new Error("Out of memory."))).toBe(true);
|
||||
expect(isMemoryExhaustionError(new Error(" Out of memory "))).toBe(true);
|
||||
});
|
||||
|
||||
// Exact-message match only — a compound message merely containing the
|
||||
// phrase (e.g. wrapped with extra context) must NOT trip this, same
|
||||
// rationale as the WebGL/GPU noise case above.
|
||||
it("does not match 'out of memory' as a mere substring of a longer message", () => {
|
||||
expect(isMemoryExhaustionError(new Error("Worker crashed: Out of memory during capture"))).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3291,7 +3291,21 @@ const MEMORY_EXHAUSTION_ERROR_PATTERNS = [
|
||||
/JavaScript heap out of memory/i,
|
||||
];
|
||||
|
||||
// The producer's deployed runtime is Bun (JavaScriptCore), not Node (V8) —
|
||||
// see `packages/gcp-cloud-run/Dockerfile`'s `CMD ["bun", "dist/server.js"]`.
|
||||
// JSC's own allocation-failure message for the equivalent single-oversized-
|
||||
// allocation RangeErrors above is the bare string "Out of memory" (verified:
|
||||
// `new Uint8Array(Number.MAX_SAFE_INTEGER)`, an unbounded `Set`, and
|
||||
// `"x".repeat(2**53)` all throw exactly this under Bun) — none of the V8
|
||||
// patterns above match it. This is exactly the substring the comment above
|
||||
// says NOT to match anywhere in the message (benign browser-console noise
|
||||
// like a WebGL `CONTEXT_LOST … out of memory` carries that phrase too), so
|
||||
// this checks the ENTIRE (trimmed) message equals it, not merely contains
|
||||
// it — a compound message with other text around the phrase still misses.
|
||||
const BUN_MEMORY_EXHAUSTION_EXACT_MESSAGE = /^out of memory\.?$/i;
|
||||
|
||||
export function isMemoryExhaustionError(error: unknown): boolean {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (BUN_MEMORY_EXHAUSTION_EXACT_MESSAGE.test(message.trim())) return true;
|
||||
return MEMORY_EXHAUSTION_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user