MCPcopy Create free account
hub / github.com/Martian-Engineering/pr-sheriff / #executeWithBackoff

Method #executeWithBackoff

src/github/github_fetch.mjs:411–451  ·  view source on GitHub ↗
(args, parseFn)

Source from the content-addressed store, hash-verified

409 }
410
411 async #executeWithBackoff(args, parseFn) {
412 // "Basics": only retry once, and only if we can infer a short wait.
413 for (let attempt = 0; attempt < 2; attempt++) {
414 const res = await this.ghRunner(args);
415 if (res.timedOut) throw new Error(`gh timed out: gh ${args.join(' ')}`);
416 if (res.exitCode !== 0 && !res.stdout) {
417 throw new Error(`gh failed (exit ${res.exitCode}): ${res.stderr || 'unknown error'}`);
418 }
419
420 const parsed = parseFn(res.stdout);
421 const status = parsed.status;
422 const headers = parsed.headers || {};
423
424 const isRateLimited =
425 status === 429 ||
426 (status === 403 && String(headers['x-ratelimit-remaining'] || '') === '0');
427
428 if (!isRateLimited || attempt === 1) return parsed;
429
430 const retryAfter = Number(headers['retry-after'] || 'NaN');
431 const resetEpoch = Number(headers['x-ratelimit-reset'] || 'NaN');
432 const nowEpoch = Math.floor(Date.now() / 1000);
433
434 let waitSeconds = Number.isFinite(retryAfter) ? retryAfter : NaN;
435 if (!Number.isFinite(waitSeconds) && Number.isFinite(resetEpoch)) {
436 waitSeconds = Math.max(0, resetEpoch - nowEpoch);
437 }
438 if (!Number.isFinite(waitSeconds)) {
439 // Can't infer; don't spin.
440 return parsed;
441 }
442
443 waitSeconds = Math.min(waitSeconds, this.maxBackoffSeconds);
444 if (waitSeconds > 0) {
445 await this.sleepFn(waitSeconds * 1000);
446 }
447 }
448
449 // Unreachable
450 throw new Error('unexpected backoff loop state');
451 }
452}
453

Callers 2

#restRequestRawMethod · 0.95
#graphqlPaginateNodesMethod · 0.95

Calls

no outgoing calls

Tested by

no test coverage detected