UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

83 lines 3.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.wrapWithRetry = wrapWithRetry; exports.getRetryAfter = getRetryAfter; const promises_1 = require("timers/promises"); const got_1 = require("got"); const luxon_1 = require("luxon"); const logger_1 = require("../../logger"); const url_1 = require("../url"); const hostDelays = new Map(); const maxRetries = 2; /** * Given a task that returns a promise, retry the task if it fails with a * 429 Too Many Requests or 403 Forbidden response, using the Retry-After * header to determine the delay. * * For response codes other than 429 or 403, or if the Retry-After header * is not present or invalid, the task is not retried, throwing the error. */ async function wrapWithRetry(task, url, getRetryAfter, maxRetryAfter) { const key = (0, url_1.parseUrl)(url)?.host ?? url; let retries = 0; for (;;) { try { await hostDelays.get(key); hostDelays.delete(key); return await task(); } catch (err) { const delaySeconds = getRetryAfter(err); if (delaySeconds === null) { throw err; } if (retries === maxRetries) { logger_1.logger.debug(`Retry-After: reached maximum retries (${maxRetries}) for ${url}`); throw err; } if (delaySeconds > maxRetryAfter) { logger_1.logger.debug(`Retry-After: delay ${delaySeconds} seconds exceeds maxRetryAfter ${maxRetryAfter} seconds for ${url}`); throw err; } logger_1.logger.debug(`Retry-After: will retry ${url} after ${delaySeconds} seconds`); const delay = Promise.all([ hostDelays.get(key), (0, promises_1.setTimeout)(1000 * delaySeconds), ]); hostDelays.set(key, delay); retries += 1; } } } function getRetryAfter(err) { if (!(err instanceof got_1.RequestError)) { return null; } if (!err.response) { return null; } if (err.response.statusCode < 400 || err.response.statusCode >= 500) { logger_1.logger.debug({ url: err.response.url }, `Retry-After: unexpected status code ${err.response.statusCode}`); return null; } const retryAfter = err.response.headers['retry-after']?.trim(); if (!retryAfter) { return null; } const date = luxon_1.DateTime.fromHTTP(retryAfter); if (date.isValid) { const seconds = Math.floor(date.diffNow('seconds').seconds); if (seconds < 0) { logger_1.logger.debug({ url: err.response.url, retryAfter }, 'Retry-After: date in the past'); return null; } return seconds; } const seconds = parseInt(retryAfter); if (!Number.isNaN(seconds) && seconds >= 0) { return seconds; } logger_1.logger.debug({ url: err.response.url, retryAfter }, 'Retry-After: unsupported format'); return null; } //# sourceMappingURL=retry-after.js.map