Skip to content

Commit 65655ad

Browse files
jrusso1020claude
andcommitted
feat(producer): also record transient-retry burn on failed renders
Addresses Via's should-fix on #1850: the transient-retry counter previously fired only on the success path ("burned budget and recovered"). Mirror it into the failure path so "burned budget and STILL failed" is also emitted — the more actionable signal for tuning MAX_TRANSIENT_CAPTURE_RETRIES. Note: `captureAttempts` was declared `const` INSIDE the try, so it was NOT in scope in the catch (contrary to the review note). Hoisted it to function scope and extracted a shared `recordTransientRetryObservability` helper called from both the success path and the catch, so the two sites can't drift. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 14feb3c commit 65655ad

1 file changed

Lines changed: 17 additions & 11 deletions

File tree

packages/producer/src/services/renderOrchestrator.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,14 @@ export async function executeRenderJob(
10371037
? "screenshot"
10381038
: "beginframe";
10391039
};
1040+
// Function-scoped (not inside the try) so both the success path AND the catch
1041+
// can read it — the catch records transient-retry burn on renders that still
1042+
// failed, which is the more actionable signal for tuning the retry cap.
1043+
const captureAttempts: CaptureAttemptSummary[] = [];
1044+
const recordTransientRetryObservability = (): void => {
1045+
const count = captureAttempts.filter((a) => a.reason === "transient-retry").length;
1046+
if (count > 0) updateCaptureObservability({ transientRetries: count });
1047+
};
10401048
// Declared outside the try so `finally` can stop the interval, but
10411049
// the sampler is created INSIDE the try so a synchronous throw
10421050
// between declaration and the try-block (currently impossible, but
@@ -1550,9 +1558,9 @@ export async function executeRenderJob(
15501558
maxDurationSeconds: cfg.streamingEncodeMaxDurationSeconds,
15511559
});
15521560

1553-
const captureAttempts: CaptureAttemptSummary[] = [];
1554-
// Static-dedup perf, appended per sequential session / per parallel worker
1555-
// by the capture stage, aggregated into the perf summary below.
1561+
// `captureAttempts` is declared at function scope above (shared with the
1562+
// catch block). Static-dedup perf, appended per sequential session / per
1563+
// parallel worker by the capture stage, aggregated into the perf summary below.
15561564
const dedupPerfs: CapturePerfSummary[] = [];
15571565

15581566
// png-sequence is "no container" — outputPath is treated as a directory and
@@ -1921,14 +1929,9 @@ export async function executeRenderJob(
19211929
const totalElapsed = Date.now() - pipelineStart;
19221930

19231931
const tmpPeakBytes = existsSync(workDir) ? sampleDirectoryBytes(workDir) : 0;
1924-
// Record how many transient-tab-death retries fired on this (successful)
1925-
// render so retry-budget burn is visible on dashboard 1783183, not just logs.
1926-
const transientRetryCount = captureAttempts.filter(
1927-
(a) => a.reason === "transient-retry",
1928-
).length;
1929-
if (transientRetryCount > 0) {
1930-
updateCaptureObservability({ transientRetries: transientRetryCount });
1931-
}
1932+
// Record transient-tab-death retry burn (recovered case) so it's visible on
1933+
// dashboard 1783183, not just logs. The catch mirrors this for the failed case.
1934+
recordTransientRetryObservability();
19321935
observability.checkpoint("pipeline", "completed", { totalElapsedMs: totalElapsed });
19331936
const observabilitySummary = observability.summary({
19341937
lastBrowserConsole,
@@ -2023,6 +2026,9 @@ export async function executeRenderJob(
20232026
if (memoryGuidance) {
20242027
updateCaptureObservability({ memoryExhaustionDetected: true });
20252028
}
2029+
// Retry burn on a render that STILL failed — the actionable signal for tuning
2030+
// MAX_TRANSIENT_CAPTURE_RETRIES (mirrors the success-path record above).
2031+
recordTransientRetryObservability();
20262032
const errorMessage = memoryGuidance ?? normalizeErrorMessage(error);
20272033
const carriedBrowserConsole = getCaptureStageBrowserConsole(error);
20282034
if (carriedBrowserConsole.length > 0) {

0 commit comments

Comments
 (0)