Octokit v22 uses native fetch, which has no built-in timeout, so a stuck GitHub request hung until the PR-status route's 12s overall budget fired — and one slow request could consume the entire budget. Wrap fetch with an 8s AbortSignal.timeout via a shared createOctokit() factory, and route the inline Octokit instantiations through it too.
34 lines
1.3 KiB
JavaScript
34 lines
1.3 KiB
JavaScript
import { Octokit } from '@octokit/rest';
|
|
import { getGitHubAuth, isGhCliActive, isGhCliDisabled } from './auth.js';
|
|
import { getGhCliToken } from './gh-cli-credential.js';
|
|
|
|
// Per-request timeout for every GitHub call. Octokit v22 uses native fetch,
|
|
// which has no built-in timeout — without this, a stuck connection hangs until
|
|
// some outer bound (the PR-status route's 12s overall budget) fires, and a
|
|
// single slow request can eat the whole budget. Bounding each request lets the
|
|
// caller fail fast and fall back to cached state instead.
|
|
const OCTOKIT_REQUEST_TIMEOUT_MS = 8000;
|
|
|
|
const timeoutFetch = (url, options = {}) => {
|
|
// Respect a caller-provided signal if present; otherwise attach our timeout.
|
|
if (options.signal) {
|
|
return fetch(url, options);
|
|
}
|
|
return fetch(url, { ...options, signal: AbortSignal.timeout(OCTOKIT_REQUEST_TIMEOUT_MS) });
|
|
};
|
|
|
|
/** Create an Octokit instance with a per-request timeout applied. */
|
|
export function createOctokit(token) {
|
|
return new Octokit({ auth: token, request: { fetch: timeoutFetch } });
|
|
}
|
|
|
|
export function getOctokitOrNull() {
|
|
const auth = getGitHubAuth();
|
|
const ghToken = !isGhCliDisabled() ? getGhCliToken() : null;
|
|
const token = isGhCliActive() ? ghToken || auth?.accessToken : auth?.accessToken || ghToken;
|
|
if (!token) {
|
|
return null;
|
|
}
|
|
return createOctokit(token);
|
|
}
|