Skip to content

Commit a57088f

Browse files
bgagentclaude
andcommitted
fix(screenshot): retry PR lookup to handle Vercel-before-PR race
Vercel posts the success `deployment_status` webhook the moment its build finishes, which on the Linear-driven path is ~7-15s before the agent's `gh pr create` returns. The processor's first lookup against the GitHub commit-pulls API came back empty and we'd silently drop the screenshot. Add a retry wrapper with backoff (0s, 5s, 10s, 20s — total max ~35s) around the PR lookup. The first hit returns immediately, so the warm-cache happy path is unchanged. Verified end-to-end on backgroundagent-dev: Linear issue ABCA-70 → agent → PR #2 in vercel-abca-linear → Vercel preview → screenshot landed on both the GitHub PR and the Linear issue. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cd6238c commit a57088f

1 file changed

Lines changed: 34 additions & 2 deletions

File tree

cdk/src/handlers/github-webhook-processor.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,13 @@ export async function handler(event: ProcessorEvent): Promise<void> {
129129
return;
130130
}
131131

132-
const pr = await findPullRequestForSha(repo, sha, token);
132+
// Race: Vercel posts `deployment_status` the moment its build finishes,
133+
// which can be ~5-15s before the agent calls `gh pr create` for the
134+
// same SHA. Retry the PR lookup with a small backoff so the screenshot
135+
// doesn't get silently dropped on what is the common path.
136+
const pr = await findPullRequestForShaWithRetry(repo, sha, token);
133137
if (!pr) {
134-
logger.info('No open PR found for SHA — skipping screenshot post', { repo, sha });
138+
logger.info('No open PR found for SHA after retries — skipping screenshot post', { repo, sha });
135139
return;
136140
}
137141

@@ -249,6 +253,34 @@ interface OpenPr {
249253
readonly body: string;
250254
}
251255

256+
/**
257+
* Wait for an open PR to exist for the given SHA, retrying with a
258+
* small backoff. Vercel commonly posts `deployment_status` before the
259+
* agent's `gh pr create` call lands (we've measured 5-15s gap), so a
260+
* single check would silently miss the common case.
261+
*
262+
* Schedule: 0s, 5s, 10s, 20s — covers the observed gap with one
263+
* generous bonus retry. Total max wait ~35s.
264+
*/
265+
async function findPullRequestForShaWithRetry(
266+
repo: string,
267+
sha: string,
268+
token: string,
269+
): Promise<OpenPr | null> {
270+
const delays = [0, 5_000, 10_000, 20_000];
271+
for (const delay of delays) {
272+
if (delay > 0) {
273+
await new Promise((r) => setTimeout(r, delay));
274+
}
275+
const pr = await findPullRequestForSha(repo, sha, token);
276+
if (pr) return pr;
277+
if (delay !== delays[delays.length - 1]) {
278+
logger.info('Open PR not found yet for SHA — will retry', { repo, sha, next_delay_ms: delays[delays.indexOf(delay) + 1] });
279+
}
280+
}
281+
return null;
282+
}
283+
252284
/**
253285
* Look up an open PR associated with `sha`. Uses the
254286
* "List pull requests associated with a commit" GitHub API

0 commit comments

Comments
 (0)