|
1 |
| -const {memoize, get} = require('lodash'); |
2 | 1 | const {Octokit} = require('@octokit/rest');
|
3 |
| -const pRetry = require('p-retry'); |
4 |
| -const Bottleneck = require('bottleneck'); |
5 | 2 | const urljoin = require('url-join');
|
6 | 3 | const HttpProxyAgent = require('http-proxy-agent');
|
7 | 4 | const HttpsProxyAgent = require('https-proxy-agent');
|
| 5 | +const {throttling} = require('@octokit/plugin-throttling'); |
| 6 | +const {RETRY_CONF} = require('./definitions/retry'); |
| 7 | +const {THROTTLE_CONF} = require('./definitions/throttle'); |
| 8 | +const {retry} = require('@octokit/plugin-retry'); |
8 | 9 |
|
9 |
| -const {RETRY_CONF, RATE_LIMITS, GLOBAL_RATE_LIMIT} = require('./definitions/rate-limit'); |
10 |
| - |
11 |
| -/** |
12 |
| - * Http error status for which to not retry. |
13 |
| - */ |
14 |
| -const SKIP_RETRY_CODES = new Set([400, 401, 403]); |
| 10 | +module.exports = ({githubToken, githubUrl, githubApiPathPrefix, proxy}) => { |
| 11 | + const onRetry = (retryAfter, options) => { |
| 12 | + github.log.warn(`Request quota exhausted for request ${options.method} ${options.url}`); |
15 | 13 |
|
16 |
| -/** |
17 |
| - * Create or retrieve the throttler function for a given rate limit group. |
18 |
| - * |
19 |
| - * @param {Array} rate The rate limit group. |
20 |
| - * @param {String} limit The rate limits per API endpoints. |
21 |
| - * @param {Bottleneck} globalThrottler The global throttler. |
22 |
| - * |
23 |
| - * @return {Bottleneck} The throller function for the given rate limit group. |
24 |
| - */ |
25 |
| -const getThrottler = memoize((rate, globalThrottler) => |
26 |
| - new Bottleneck({minTime: get(RATE_LIMITS, rate)}).chain(globalThrottler) |
27 |
| -); |
| 14 | + if (options.request.retryCount <= RETRY_CONF.retries) { |
| 15 | + github.log.debug(`Will retry after ${retryAfter}.`); |
| 16 | + return true; |
| 17 | + } |
| 18 | + }; |
28 | 19 |
|
29 |
| -module.exports = ({githubToken, githubUrl, githubApiPathPrefix, proxy}) => { |
30 | 20 | const baseUrl = githubUrl && urljoin(githubUrl, githubApiPathPrefix);
|
31 |
| - const globalThrottler = new Bottleneck({minTime: GLOBAL_RATE_LIMIT}); |
32 |
| - const github = new Octokit({ |
| 21 | + const OctokitWithThrottlingAndRetry = Octokit.plugin(throttling, retry); |
| 22 | + const github = new OctokitWithThrottlingAndRetry({ |
33 | 23 | auth: `token ${githubToken}`,
|
34 | 24 | baseUrl,
|
| 25 | + retry: RETRY_CONF, |
35 | 26 | request: {
|
36 | 27 | agent: proxy
|
37 | 28 | ? baseUrl && new URL(baseUrl).protocol.replace(':', '') === 'http'
|
38 | 29 | ? new HttpProxyAgent(proxy)
|
39 | 30 | : new HttpsProxyAgent(proxy)
|
40 | 31 | : undefined,
|
41 | 32 | },
|
42 |
| - }); |
43 |
| - |
44 |
| - github.hook.wrap('request', (request, options) => { |
45 |
| - const access = options.method === 'GET' ? 'read' : 'write'; |
46 |
| - const rateCategory = options.url.startsWith('/search') ? 'search' : 'core'; |
47 |
| - const limitKey = [rateCategory, RATE_LIMITS[rateCategory][access] && access].filter(Boolean).join('.'); |
48 |
| - |
49 |
| - return pRetry(async () => { |
50 |
| - try { |
51 |
| - return await getThrottler(limitKey, globalThrottler).wrap(request)(options); |
52 |
| - } catch (error) { |
53 |
| - if (SKIP_RETRY_CODES.has(error.status)) { |
54 |
| - throw new pRetry.AbortError(error); |
55 |
| - } |
56 |
| - |
57 |
| - throw error; |
58 |
| - } |
59 |
| - }, RETRY_CONF); |
| 33 | + throttle: { |
| 34 | + ...THROTTLE_CONF, |
| 35 | + onSecondaryRateLimit: onRetry, |
| 36 | + onRateLimit: onRetry, |
| 37 | + }, |
60 | 38 | });
|
61 | 39 |
|
62 | 40 | return github;
|
|
0 commit comments