1 | # plugin-throttling.js
|
2 |
|
3 | > Octokit plugin for GitHub’s recommended request throttling
|
4 |
|
5 | [![npm](https://img.shields.io/npm/v/@octokit/plugin-throttling.svg)](https://www.npmjs.com/package/@octokit/plugin-throttling)
|
6 | [![Build Status](https://travis-ci.com/octokit/plugin-throttling.js.svg)](https://travis-ci.com/octokit/plugin-throttling.js)
|
7 | [![Coverage Status](https://img.shields.io/coveralls/github/octokit/plugin-throttling.js.svg)](https://coveralls.io/github/octokit/plugin-throttling.js)
|
8 | [![Greenkeeper](https://badges.greenkeeper.io/octokit/plugin-throttling.js.svg)](https://greenkeeper.io/)
|
9 |
|
10 | Implements all [recommended best practises](https://developer.github.com/v3/guides/best-practices-for-integrators/) to prevent hitting abuse rate limits.
|
11 |
|
12 | ## Usage
|
13 |
|
14 | The code below creates a "Hello, world!" issue on every repository in a given organization. Without the throttling plugin it would send many requests in parallel and would hit rate limits very quickly. But the `@octokit/plugin-throttling` slows down your requests according to the official guidelines, so you don't get blocked before your quota is exhausted.
|
15 |
|
16 | The `throttle.onAbuseLimit` and `throttle.onRateLimit` options are required. Return `true` to automatically retry the request after `retryAfter` seconds.
|
17 |
|
18 | ```js
|
19 | const Octokit = require('@octokit/rest')
|
20 | .plugin(require('@octokit/plugin-throttling'))
|
21 |
|
22 | const octokit = new Octokit({
|
23 | throttle: {
|
24 | onRateLimit: (retryAfter, options) => {
|
25 | console.warn(`Request quota exhausted for request ${options.method} ${options.url}`)
|
26 |
|
27 | if (options.request.retryCount === 0) { // only retries once
|
28 | console.log(`Retrying after ${retryAfter} seconds!`)
|
29 | return true
|
30 | }
|
31 | },
|
32 | onAbuseLimit: (retryAfter, options) => {
|
33 | // does not retry, only logs a warning
|
34 | console.warn(`Abuse detected for request ${options.method} ${options.url}`)
|
35 | }
|
36 | }
|
37 | })
|
38 |
|
39 | octokit.authenticate({
|
40 | type: 'token',
|
41 | token: process.env.TOKEN
|
42 | })
|
43 |
|
44 | async function createIssueOnAllRepos (org) {
|
45 | const repos = await octokit.paginate(octokit.repos.listForOrg.endpoint({ org }))
|
46 | return Promise.all(repos.forEach(({ name } => {
|
47 | octokit.issues.create({
|
48 | owner,
|
49 | repo: name,
|
50 | title: 'Hello, world!'
|
51 | })
|
52 | })))
|
53 | }
|
54 | ```
|
55 |
|
56 | Pass `{ throttle: { enabled: false } }` to disable this plugin.
|
57 |
|
58 | ### Clustering
|
59 |
|
60 | Enabling Clustering support ensures that your application will not go over rate limits **across Octokit instances and across Nodejs processes**.
|
61 |
|
62 | First install either `redis` or `ioredis`:
|
63 | ```
|
64 | # NodeRedis (https://github.com/NodeRedis/node_redis)
|
65 | npm install --save redis
|
66 |
|
67 | # or ioredis (https://github.com/luin/ioredis)
|
68 | npm install --save ioredis
|
69 | ```
|
70 |
|
71 | Then in your application:
|
72 | ```js
|
73 | const Bottleneck = require('bottleneck')
|
74 | const Redis = require('redis')
|
75 |
|
76 | const client = Redis.createClient({ /* options */ })
|
77 | const connection = new Bottleneck.RedisConnection({ client })
|
78 | connection.on('error', err => console.error(err))
|
79 |
|
80 | const octokit = new Octokit({
|
81 | throttle: {
|
82 | onAbuseLimit: (retryAfter, options) => { /* ... */ },
|
83 | onRateLimit: (retryAfter, options) => { /* ... */ },
|
84 |
|
85 | // The Bottleneck connection object
|
86 | connection,
|
87 |
|
88 | // A "throttling ID". All octokit instances with the same ID
|
89 | // using the same Redis server will share the throttling.
|
90 | id: 'my-super-app',
|
91 |
|
92 | // Otherwise the plugin uses a lighter version of Bottleneck without Redis support
|
93 | Bottleneck
|
94 | }
|
95 | })
|
96 |
|
97 | // To close the connection and allow your application to exit cleanly:
|
98 | await connection.disconnect()
|
99 | ```
|
100 |
|
101 | To use the `ioredis` library instead:
|
102 | ```js
|
103 | const Redis = require('ioredis')
|
104 | const client = new Redis({ /* options */ })
|
105 | const connection = new Bottleneck.IORedisConnection({ client })
|
106 | connection.on('error', err => console.error(err))
|
107 | ```
|
108 |
|
109 | ## LICENSE
|
110 |
|
111 | [MIT](LICENSE)
|