Skip to content

Commit 5c17b5b

Browse files
committed
feat: add @octokit/plugin-retry to handle retriable server errors
Add the retry plugin to automatically retry requests that fail with server errors (5xx status codes). Configure the plugin to exclude 429 (rate limit) from retries since that is already handled by the throttling plugin. - Add @octokit/plugin-retry dependency - Register retry plugin in Octokit client - Export retryOptions with doNotRetry list excluding 429 - Apply retryOptions in GitHubHelper constructor
1 parent 34aa40e commit 5c17b5b

5 files changed

Lines changed: 215 additions & 49 deletions

File tree

dist/index.js

Lines changed: 157 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,7 @@ class GitHubHelper {
13901390
options.baseUrl = 'https://api.github.com';
13911391
}
13921392
options.throttle = octokit_client_1.throttleOptions;
1393+
options.retry = octokit_client_1.retryOptions;
13931394
this.octokit = new octokit_client_1.Octokit(options);
13941395
}
13951396
parseRepository(repository) {
@@ -1819,14 +1820,15 @@ var __importStar = (this && this.__importStar) || (function () {
18191820
};
18201821
})();
18211822
Object.defineProperty(exports, "__esModule", ({ value: true }));
1822-
exports.throttleOptions = exports.Octokit = void 0;
1823+
exports.retryOptions = exports.throttleOptions = exports.Octokit = void 0;
18231824
const core = __importStar(__nccwpck_require__(7484));
1824-
const core_1 = __nccwpck_require__(767);
1825+
const core_1 = __nccwpck_require__(708);
18251826
const plugin_paginate_rest_1 = __nccwpck_require__(3779);
18261827
const plugin_rest_endpoint_methods_1 = __nccwpck_require__(9210);
1828+
const plugin_retry_1 = __nccwpck_require__(9735);
18271829
const plugin_throttling_1 = __nccwpck_require__(6856);
18281830
const proxy_1 = __nccwpck_require__(3459);
1829-
exports.Octokit = core_1.Octokit.plugin(plugin_paginate_rest_1.paginateRest, plugin_rest_endpoint_methods_1.restEndpointMethods, plugin_throttling_1.throttling, autoProxyAgent);
1831+
exports.Octokit = core_1.Octokit.plugin(plugin_paginate_rest_1.paginateRest, plugin_rest_endpoint_methods_1.restEndpointMethods, plugin_retry_1.retry, plugin_throttling_1.throttling, autoProxyAgent);
18301832
exports.throttleOptions = {
18311833
onRateLimit: (retryAfter, options, _, retryCount) => {
18321834
core.debug(`Hit rate limit for request ${options.method} ${options.url}`);
@@ -1841,6 +1843,10 @@ exports.throttleOptions = {
18411843
core.warning(`Requests may be retried after ${retryAfter} seconds.`);
18421844
}
18431845
};
1846+
exports.retryOptions = {
1847+
// 429 is handled by the throttling plugin, so we exclude it from retry
1848+
doNotRetry: [400, 401, 403, 404, 410, 422, 429, 451]
1849+
};
18441850
// Octokit plugin to support the standard environment variables http_proxy, https_proxy and no_proxy
18451851
function autoProxyAgent(octokit) {
18461852
octokit.hook.before('request', options => {
@@ -32216,7 +32222,7 @@ module.exports = fetch;
3221632222

3221732223
/***/ }),
3221832224

32219-
/***/ 767:
32225+
/***/ 708:
3222032226
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
3222132227

3222232228
"use strict";
@@ -32736,46 +32742,8 @@ var endpoint = withDefaults(null, DEFAULTS);
3273632742

3273732743
// EXTERNAL MODULE: ./node_modules/fast-content-type-parse/index.js
3273832744
var fast_content_type_parse = __nccwpck_require__(8739);
32739-
;// CONCATENATED MODULE: ./node_modules/@octokit/request-error/dist-src/index.js
32740-
class RequestError extends Error {
32741-
name;
32742-
/**
32743-
* http status code
32744-
*/
32745-
status;
32746-
/**
32747-
* Request options that lead to the error.
32748-
*/
32749-
request;
32750-
/**
32751-
* Response object if a response was received
32752-
*/
32753-
response;
32754-
constructor(message, statusCode, options) {
32755-
super(message);
32756-
this.name = "HttpError";
32757-
this.status = Number.parseInt(statusCode);
32758-
if (Number.isNaN(this.status)) {
32759-
this.status = 0;
32760-
}
32761-
if ("response" in options) {
32762-
this.response = options.response;
32763-
}
32764-
const requestCopy = Object.assign({}, options.request);
32765-
if (options.request.headers.authorization) {
32766-
requestCopy.headers = Object.assign({}, options.request.headers, {
32767-
authorization: options.request.headers.authorization.replace(
32768-
/(?<! ) .*$/,
32769-
" [REDACTED]"
32770-
)
32771-
});
32772-
}
32773-
requestCopy.url = requestCopy.url.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]").replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
32774-
this.request = requestCopy;
32775-
}
32776-
}
32777-
32778-
32745+
// EXTERNAL MODULE: ./node_modules/@octokit/request-error/dist-src/index.js
32746+
var dist_src = __nccwpck_require__(1015);
3277932747
;// CONCATENATED MODULE: ./node_modules/@octokit/request/dist-bundle/index.js
3278032748
// pkg/dist-src/index.js
3278132749

@@ -32852,7 +32820,7 @@ async function fetchWrapper(requestOptions) {
3285232820
}
3285332821
}
3285432822
}
32855-
const requestError = new RequestError(message, 500, {
32823+
const requestError = new dist_src/* RequestError */.G(message, 500, {
3285632824
request: requestOptions
3285732825
});
3285832826
requestError.cause = error;
@@ -32884,21 +32852,21 @@ async function fetchWrapper(requestOptions) {
3288432852
if (status < 400) {
3288532853
return octokitResponse;
3288632854
}
32887-
throw new RequestError(fetchResponse.statusText, status, {
32855+
throw new dist_src/* RequestError */.G(fetchResponse.statusText, status, {
3288832856
response: octokitResponse,
3288932857
request: requestOptions
3289032858
});
3289132859
}
3289232860
if (status === 304) {
3289332861
octokitResponse.data = await getResponseData(fetchResponse);
32894-
throw new RequestError("Not modified", status, {
32862+
throw new dist_src/* RequestError */.G("Not modified", status, {
3289532863
response: octokitResponse,
3289632864
request: requestOptions
3289732865
});
3289832866
}
3289932867
if (status >= 400) {
3290032868
octokitResponse.data = await getResponseData(fetchResponse);
32901-
throw new RequestError(toErrorMessage(octokitResponse.data), status, {
32869+
throw new dist_src/* RequestError */.G(toErrorMessage(octokitResponse.data), status, {
3290232870
response: octokitResponse,
3290332871
request: requestOptions
3290432872
});
@@ -36195,6 +36163,98 @@ legacyRestEndpointMethods.VERSION = VERSION;
3619536163
//# sourceMappingURL=index.js.map
3619636164

3619736165

36166+
/***/ }),
36167+
36168+
/***/ 9735:
36169+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
36170+
36171+
"use strict";
36172+
__nccwpck_require__.r(__webpack_exports__);
36173+
/* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
36174+
/* harmony export */ VERSION: () => (/* binding */ VERSION),
36175+
/* harmony export */ retry: () => (/* binding */ retry)
36176+
/* harmony export */ });
36177+
/* harmony import */ var bottleneck_light_js__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(3251);
36178+
/* harmony import */ var _octokit_request_error__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(1015);
36179+
// pkg/dist-src/version.js
36180+
var VERSION = "0.0.0-development";
36181+
36182+
// pkg/dist-src/error-request.js
36183+
async function errorRequest(state, octokit, error, options) {
36184+
if (!error.request || !error.request.request) {
36185+
throw error;
36186+
}
36187+
if (error.status >= 400 && !state.doNotRetry.includes(error.status)) {
36188+
const retries = options.request.retries != null ? options.request.retries : state.retries;
36189+
const retryAfter = Math.pow((options.request.retryCount || 0) + 1, 2);
36190+
throw octokit.retry.retryRequest(error, retries, retryAfter);
36191+
}
36192+
throw error;
36193+
}
36194+
36195+
// pkg/dist-src/wrap-request.js
36196+
36197+
36198+
async function wrapRequest(state, octokit, request, options) {
36199+
const limiter = new bottleneck_light_js__WEBPACK_IMPORTED_MODULE_0__();
36200+
limiter.on("failed", function(error, info) {
36201+
const maxRetries = ~~error.request.request.retries;
36202+
const after = ~~error.request.request.retryAfter;
36203+
options.request.retryCount = info.retryCount + 1;
36204+
if (maxRetries > info.retryCount) {
36205+
return after * state.retryAfterBaseValue;
36206+
}
36207+
});
36208+
return limiter.schedule(
36209+
requestWithGraphqlErrorHandling.bind(null, state, octokit, request),
36210+
options
36211+
);
36212+
}
36213+
async function requestWithGraphqlErrorHandling(state, octokit, request, options) {
36214+
const response = await request(request, options);
36215+
if (response.data && response.data.errors && response.data.errors.length > 0 && /Something went wrong while executing your query/.test(
36216+
response.data.errors[0].message
36217+
)) {
36218+
const error = new _octokit_request_error__WEBPACK_IMPORTED_MODULE_1__/* .RequestError */ .G(response.data.errors[0].message, 500, {
36219+
request: options,
36220+
response
36221+
});
36222+
return errorRequest(state, octokit, error, options);
36223+
}
36224+
return response;
36225+
}
36226+
36227+
// pkg/dist-src/index.js
36228+
function retry(octokit, octokitOptions) {
36229+
const state = Object.assign(
36230+
{
36231+
enabled: true,
36232+
retryAfterBaseValue: 1e3,
36233+
doNotRetry: [400, 401, 403, 404, 410, 422, 451],
36234+
retries: 3
36235+
},
36236+
octokitOptions.retry
36237+
);
36238+
if (state.enabled) {
36239+
octokit.hook.error("request", errorRequest.bind(null, state, octokit));
36240+
octokit.hook.wrap("request", wrapRequest.bind(null, state, octokit));
36241+
}
36242+
return {
36243+
retry: {
36244+
retryRequest: (error, retries, retryAfter) => {
36245+
error.request.request = Object.assign({}, error.request.request, {
36246+
retries,
36247+
retryAfter
36248+
});
36249+
return error;
36250+
}
36251+
}
36252+
};
36253+
}
36254+
retry.VERSION = VERSION;
36255+
36256+
36257+
3619836258
/***/ }),
3619936259

3620036260
/***/ 6856:
@@ -36434,6 +36494,55 @@ throttling.triggersNotification = triggersNotification;
3643436494

3643536495

3643636496

36497+
/***/ }),
36498+
36499+
/***/ 1015:
36500+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __nccwpck_require__) => {
36501+
36502+
"use strict";
36503+
/* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
36504+
/* harmony export */ G: () => (/* binding */ RequestError)
36505+
/* harmony export */ });
36506+
class RequestError extends Error {
36507+
name;
36508+
/**
36509+
* http status code
36510+
*/
36511+
status;
36512+
/**
36513+
* Request options that lead to the error.
36514+
*/
36515+
request;
36516+
/**
36517+
* Response object if a response was received
36518+
*/
36519+
response;
36520+
constructor(message, statusCode, options) {
36521+
super(message);
36522+
this.name = "HttpError";
36523+
this.status = Number.parseInt(statusCode);
36524+
if (Number.isNaN(this.status)) {
36525+
this.status = 0;
36526+
}
36527+
if ("response" in options) {
36528+
this.response = options.response;
36529+
}
36530+
const requestCopy = Object.assign({}, options.request);
36531+
if (options.request.headers.authorization) {
36532+
requestCopy.headers = Object.assign({}, options.request.headers, {
36533+
authorization: options.request.headers.authorization.replace(
36534+
/(?<! ) .*$/,
36535+
" [REDACTED]"
36536+
)
36537+
});
36538+
}
36539+
requestCopy.url = requestCopy.url.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]").replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
36540+
this.request = requestCopy;
36541+
}
36542+
}
36543+
36544+
36545+
3643736546
/***/ }),
3643836547

3643936548
/***/ 7989:

0 commit comments

Comments
 (0)