Skip to content

Commit 2a61d95

Browse files
pvdlggr2m
authored andcommitted
fix: replace p-throttle with bottleneck
1 parent c8ab3fb commit 2a61d95

File tree

8 files changed

+37
-35
lines changed

8 files changed

+37
-35
lines changed

lib/get-client.js

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const url = require('url');
22
const {memoize} = require('lodash');
33
const Octokit = require('@octokit/rest');
44
const pRetry = require('p-retry');
5-
const pThrottle = require('p-throttle');
5+
const Bottleneck = require('bottleneck');
66

77
/**
88
* Default exponential backoff configuration for retries.
@@ -16,44 +16,33 @@ const DEFAULT_RETRY = {retries: 3, factor: 2, minTimeout: 1000};
1616
* See {@link https://developer.github.com/v3/#rate-limiting|Rate limiting}.
1717
*/
1818
const RATE_LIMITS = {
19-
search: [30, 60 * 1000],
20-
core: [5000, 60 * 60 * 1000],
19+
search: 60 * 1000 / 30, // 30 calls per minutes => 1 call per 2s
20+
core: 60 * 60 * 1000 / 5000, // 5000 calls per hour => 1 call per 720ms
2121
};
2222

2323
/**
2424
* Global rate limit to prevent abuse.
2525
*
2626
* See {@link https://developer.github.com/v3/guides/best-practices-for-integrators/#dealing-with-abuse-rate-limits|Dealing with abuse rate limits}
2727
*/
28-
const GLOBAL_RATE_LIMIT = [1, 1000];
28+
const GLOBAL_RATE_LIMIT = 1000;
2929

3030
/**
3131
* Http error codes for which to not retry.
3232
*/
3333
const SKIP_RETRY_CODES = [400, 401, 403];
3434

35-
/**
36-
* @typedef {Function} Throttler
37-
* @param {Function} func The function to throttle.
38-
* @param {Arguments} args The arguments to pass to the function to throttle.
39-
*/
40-
4135
/**
4236
* Create or retrieve the throttler function for a given rate limit group.
4337
*
4438
* @param {Array} rate The rate limit group.
4539
* @param {String} limit The rate limits per API endpoints.
46-
* @return {Throttler} The throller function for the given rate limit group.
47-
*/
48-
const getThrottler = memoize((rate, limit) => pThrottle((func, ...args) => func(...args), ...limit[rate]));
49-
50-
/**
51-
* Create the global throttler function to comply with GitHub abuse prevention recommandations.
52-
*
53-
* @param {Array} globalLimit The global rate limit.
54-
* @return {Throttler} The throller function for the global rate limit.
40+
* @param {Bottleneck} globalThrottler The global throttler.
41+
* @return {Bottleneck} The throller function for the given rate limit group.
5542
*/
56-
const getGlobalThrottler = globalLimit => pThrottle((func, ...args) => func(...args), ...globalLimit);
43+
const getThrottler = memoize((rate, limit, globalThrottler) =>
44+
new Bottleneck({minTime: limit[rate]}).chain(globalThrottler)
45+
);
5746

5847
/**
5948
* Create a`handler` for a `Proxy` wrapping an Octokit instance to:
@@ -89,11 +78,11 @@ const handler = (retry, limit, globalThrottler, endpoint) => ({
8978
* @return {Promise<Any>} The result of the function called.
9079
*/
9180
apply: (func, that, args) => {
92-
const throttler = getThrottler(limit[endpoint] ? endpoint : 'core', limit);
81+
const throttler = getThrottler(limit[endpoint] ? endpoint : 'core', limit, globalThrottler);
9382

9483
return pRetry(async () => {
9584
try {
96-
return await globalThrottler((func, ...args) => throttler(func, ...args), func, ...args);
85+
return await throttler.wrap(func)(...args);
9786
} catch (err) {
9887
if (SKIP_RETRY_CODES.includes(err.code)) {
9988
throw new pRetry.AbortError(err);
@@ -120,5 +109,5 @@ module.exports = ({
120109
pathPrefix: githubApiPathPrefix,
121110
});
122111
github.authenticate({type: 'token', token: githubToken});
123-
return new Proxy(github, handler(retry, limit, getGlobalThrottler(globalLimit)));
112+
return new Proxy(github, handler(retry, limit, new Bottleneck({minTime: globalLimit})));
124113
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
"@octokit/rest": "^14.0.9",
2020
"@semantic-release/error": "^2.2.0",
2121
"aggregate-error": "^1.0.0",
22+
"bottleneck": "^2.0.1",
2223
"debug": "^3.1.0",
2324
"fs-extra": "^5.0.0",
2425
"globby": "^8.0.0",
2526
"issue-parser": "^1.0.1",
2627
"lodash": "^4.17.4",
2728
"mime": "^2.0.3",
2829
"p-retry": "^1.0.0",
29-
"p-throttle": "^1.1.0",
3030
"parse-github-url": "^1.0.1",
3131
"url-join": "^4.0.0"
3232
},

test/fail.test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import {authenticate} from './helpers/mock-github';
1212

1313
const fail = proxyquire('../lib/fail', {
1414
'./get-client': conf =>
15-
getClient({...conf, ...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, globalLimit: [99, 1]}}),
15+
getClient({
16+
...conf,
17+
...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, limit: {search: 1, core: 1}, globalLimit: 1},
18+
}),
1619
});
1720

1821
// Save the current process.env

test/find-sr-issue.test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ const githubToken = 'github_token';
1515
const client = getClient({
1616
githubToken,
1717
retry: {retries: 3, factor: 2, minTimeout: 1, maxTimeout: 1},
18-
globalLimit: [99, 1],
18+
globalLimit: 1,
19+
limit: {search: 1, core: 1},
1920
});
2021

2122
test.beforeEach(t => {

test/get-client.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ test('Use the global throttler for all endpoints', async t => {
2727
const octokit = {repos: {createRelease}, issues: {createComment}, search: {issues}, authenticate: stub()};
2828
const rate = 150;
2929
const github = proxyquire('../lib/get-client', {'@octokit/rest': stub().returns(octokit)})({
30-
limit: {search: [99, 1], core: [99, 1]},
31-
globalLimit: [1, rate],
30+
limit: {search: 1, core: 1},
31+
globalLimit: rate,
3232
});
3333

3434
const a = await github.repos.createRelease();
@@ -58,8 +58,8 @@ test('Use the same throttler for endpoints in the same rate limit group', async
5858
const searchRate = 300;
5959
const coreRate = 150;
6060
const github = proxyquire('../lib/get-client', {'@octokit/rest': stub().returns(octokit)})({
61-
limit: {search: [1, searchRate], core: [1, coreRate]},
62-
globalLimit: [99, 1],
61+
limit: {search: searchRate, core: coreRate},
62+
globalLimit: 1,
6363
});
6464

6565
const a = await github.repos.createRelease();
@@ -93,9 +93,9 @@ test('Use the same throttler when retrying', async t => {
9393
const octokit = {repos: {createRelease}, authenticate: stub()};
9494
const coreRate = 200;
9595
const github = proxyquire('../lib/get-client', {'@octokit/rest': stub().returns(octokit)})({
96-
limit: {core: [1, coreRate]},
96+
limit: {core: coreRate},
9797
retry: {retries: 3, factor: 1, minTimeout: 1},
98-
globalLimit: [6, 1],
98+
globalLimit: 1,
9999
});
100100

101101
await t.throws(github.repos.createRelease());

test/publish.test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import {authenticate, upload} from './helpers/mock-github';
1212

1313
const publish = proxyquire('../lib/publish', {
1414
'./get-client': conf =>
15-
getClient({...conf, ...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, globalLimit: [99, 1]}}),
15+
getClient({
16+
...conf,
17+
...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, limit: {search: 1, core: 1}, globalLimit: 1},
18+
}),
1619
});
1720

1821
// Save the current process.env

test/success.test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import {authenticate} from './helpers/mock-github';
1212

1313
const success = proxyquire('../lib/success', {
1414
'./get-client': conf =>
15-
getClient({...conf, ...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, globalLimit: [99, 1]}}),
15+
getClient({
16+
...conf,
17+
...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, limit: {search: 1, core: 1}, globalLimit: 1},
18+
}),
1619
});
1720

1821
// Save the current process.env

test/verify.test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ const envBackup = Object.assign({}, process.env);
1010

1111
const verify = proxyquire('../lib/verify', {
1212
'./get-client': conf =>
13-
getClient({...conf, ...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, globalLimit: [99, 1]}}),
13+
getClient({
14+
...conf,
15+
...{retry: {retries: 3, factor: 1, minTimeout: 1, maxTimeout: 1}, limit: {search: 1, core: 1}, globalLimit: 1},
16+
}),
1417
});
1518

1619
test.beforeEach(t => {

0 commit comments

Comments
 (0)