Skip to content

Commit 769c1f2

Browse files
SGrondingr2m
authored andcommitted
feat: global limiter caching (#22)
1 parent e745138 commit 769c1f2

File tree

3 files changed

+39
-29
lines changed

3 files changed

+39
-29
lines changed

lib/index.js

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,53 @@ const routeMatcher = require('./route-matcher')(triggersNotificationPaths)
99
const triggersNotification = throttlingPlugin.triggersNotification =
1010
routeMatcher.test.bind(routeMatcher)
1111

12+
const groups = {}
13+
14+
const createGroups = function (Bottleneck, common) {
15+
groups.global = new Bottleneck.Group({
16+
id: 'octokit-global',
17+
maxConcurrent: 1,
18+
...common
19+
})
20+
groups.write = new Bottleneck.Group({
21+
id: 'octokit-write',
22+
maxConcurrent: 1,
23+
minTime: 1000,
24+
...common
25+
})
26+
groups.notifications = new Bottleneck.Group({
27+
id: 'octokit-notifications',
28+
maxConcurrent: 1,
29+
minTime: 3000,
30+
...common
31+
})
32+
}
33+
1234
function throttlingPlugin (octokit, octokitOptions = {}) {
1335
const {
1436
enabled = true,
1537
Bottleneck = BottleneckLight,
1638
id = 'no-id',
39+
timeout = 1000 * 60 * 2, // Redis TTL: 2 minutes
1740
connection
1841
} = octokitOptions.throttle || {}
1942
if (!enabled) {
2043
return
2144
}
22-
const common = {
23-
connection,
24-
timeout: 1000 * 60 * 10 // Redis TTL: 10 minutes
45+
const common = { connection, timeout }
46+
47+
if (groups.global == null) {
48+
createGroups(Bottleneck, common)
2549
}
50+
2651
const state = Object.assign({
2752
clustering: connection != null,
2853
triggersNotification,
2954
minimumAbuseRetryAfter: 5,
3055
retryAfterBaseValue: 1000,
31-
globalLimiter: new Bottleneck({
32-
id: `octokit-global-${id}`,
33-
maxConcurrent: 1,
34-
...common
35-
}),
36-
writeLimiter: new Bottleneck({
37-
id: `octokit-write-${id}`,
38-
maxConcurrent: 1,
39-
minTime: 1000,
40-
...common
41-
}),
42-
triggersNotificationLimiter: new Bottleneck({
43-
id: `octokit-notifications-${id}`,
44-
maxConcurrent: 1,
45-
minTime: 3000,
46-
...common
47-
}),
48-
retryLimiter: new Bottleneck()
56+
retryLimiter: new Bottleneck(),
57+
id,
58+
...groups
4959
}, octokitOptions.throttle)
5060

5161
if (typeof state.onAbuseLimit !== 'function' || typeof state.onRateLimit !== 'function') {

lib/wrap-request.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ async function doRequest (state, request, options) {
1818

1919
// Guarantee at least 1000ms between writes
2020
if (isWrite) {
21-
await state.writeLimiter.schedule(jobOptions, noop)
21+
await state.write.key(state.id).schedule(jobOptions, noop)
2222
}
2323

2424
// Guarantee at least 3000ms between requests that trigger notifications
2525
if (isWrite && state.triggersNotification(options.url)) {
26-
await state.triggersNotificationLimiter.schedule(jobOptions, noop)
26+
await state.notifications.key(state.id).schedule(jobOptions, noop)
2727
}
2828

29-
return state.globalLimiter.schedule(jobOptions, request, options)
29+
return state.global.key(state.id).schedule(jobOptions, request, options)
3030
}

test/integration/index.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ describe('Github API best practices', function () {
8383
it('Should maintain 1000ms between mutating requests', async function () {
8484
const octokit = new Octokit({
8585
throttle: {
86-
writeLimiter: new Bottleneck({ minTime: 50 }),
86+
write: new Bottleneck.Group({ minTime: 50 }),
8787
onAbuseLimit: () => 1,
8888
onRateLimit: () => 1
8989
}
@@ -120,8 +120,8 @@ describe('Github API best practices', function () {
120120
it('Should maintain 3000ms between requests that trigger notifications', async function () {
121121
const octokit = new Octokit({
122122
throttle: {
123-
writeLimiter: new Bottleneck({ minTime: 50 }),
124-
triggersNotificationLimiter: new Bottleneck({ minTime: 100 }),
123+
write: new Bottleneck.Group({ minTime: 50 }),
124+
notifications: new Bottleneck.Group({ minTime: 100 }),
125125
onAbuseLimit: () => 1,
126126
onRateLimit: () => 1
127127
}
@@ -175,8 +175,8 @@ describe('Github API best practices', function () {
175175
it('Should optimize throughput rather than maintain ordering', async function () {
176176
const octokit = new Octokit({
177177
throttle: {
178-
writeLimiter: new Bottleneck({ minTime: 50 }),
179-
triggersNotificationLimiter: new Bottleneck({ minTime: 100 }),
178+
write: new Bottleneck.Group({ minTime: 50 }),
179+
notifications: new Bottleneck.Group({ minTime: 100 }),
180180
onAbuseLimit: () => 1,
181181
onRateLimit: () => 1
182182
}

0 commit comments

Comments
 (0)