forked from mirrors/probot
feat: Cluster support for request throttling
This commit is contained in:
parent
b0f0f50602
commit
86f5312ad5
|
@ -34,6 +34,7 @@ export class Application {
|
|||
public cache: Cache
|
||||
public router: express.Router
|
||||
public log: LoggerWithTarget
|
||||
public throttleOptions: any
|
||||
|
||||
private githubToken?: string
|
||||
|
||||
|
@ -46,6 +47,20 @@ export class Application {
|
|||
this.router = opts.router || express.Router() // you can do this?
|
||||
this.githubToken = opts.githubToken
|
||||
|
||||
if (process.env.REDIS_URL) {
|
||||
const Bottleneck = require('bottleneck')
|
||||
const Redis = require('ioredis')
|
||||
|
||||
const client = new Redis(process.env.REDIS_URL)
|
||||
const connection = new Bottleneck.IORedisConnection({ client })
|
||||
connection.on('error', this.log.error)
|
||||
|
||||
this.throttleOptions = {
|
||||
Bottleneck,
|
||||
connection
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.catchErrors) {
|
||||
// Deprecated since 7.2.0
|
||||
// tslint:disable-next-line:no-console
|
||||
|
@ -195,26 +210,35 @@ export class Application {
|
|||
// if installation ID passed, instantiate and authenticate Octokit, then cache the instance
|
||||
// so that it can be used across received webhook events.
|
||||
if (id) {
|
||||
const options = {
|
||||
auth: async () => {
|
||||
const accessToken = await this.app.getInstallationAccessToken({ installationId: id })
|
||||
return `token ${accessToken}`
|
||||
},
|
||||
baseUrl: process.env.GHE_HOST && `https://${process.env.GHE_HOST}/api/v3`,
|
||||
logger: log.child({ name: 'github', installation: String(id) })
|
||||
}
|
||||
|
||||
if (this.throttleOptions) {
|
||||
return GitHubAPI({
|
||||
...options,
|
||||
throttle: {
|
||||
id,
|
||||
...this.throttleOptions
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Cache for 1 minute less than GitHub expiry
|
||||
const installationTokenTTL = parseInt(process.env.INSTALLATION_TOKEN_TTL || '3540', 10)
|
||||
|
||||
return this.cache.wrap(`app:${id}`, async () => {
|
||||
return GitHubAPI({
|
||||
auth: async () => {
|
||||
const accessToken = await this.app.getInstallationAccessToken({ installationId: id })
|
||||
return `token ${accessToken}`
|
||||
},
|
||||
baseUrl: process.env.GHE_HOST && `https://${process.env.GHE_HOST}/api/v3`,
|
||||
logger: log.child({ name: 'github', installation: String(id) })
|
||||
})
|
||||
}, { ttl: installationTokenTTL })
|
||||
return this.cache.wrap(`app:${id}`, () => GitHubAPI(options), { ttl: installationTokenTTL })
|
||||
}
|
||||
|
||||
const token = this.githubToken || this.app.getSignedJsonWebToken()
|
||||
const github = GitHubAPI({
|
||||
auth: `Bearer ${token}`,
|
||||
baseUrl: process.env.GHE_HOST && `https://${process.env.GHE_HOST}/api/v3`,
|
||||
logger: log.child({ name: 'github', installation: String(id) })
|
||||
logger: log.child({ name: 'github' })
|
||||
})
|
||||
|
||||
return github
|
||||
|
|
|
@ -21,10 +21,10 @@ const ProbotOctokit = Octokit
|
|||
*/
|
||||
export function GitHubAPI (options: Options = {} as any) {
|
||||
const octokit = new ProbotOctokit(Object.assign(options, {
|
||||
throttle: {
|
||||
throttle: Object.assign({
|
||||
onAbuseLimit: (retryAfter: number) => options.logger.warn(`Abuse limit hit, retrying in ${retryAfter} seconds`),
|
||||
onRateLimit: (retryAfter: number) => options.logger.warn(`Rate limit hit, retrying in ${retryAfter} seconds`)
|
||||
}
|
||||
}, options.throttle)
|
||||
})) as GitHubAPI
|
||||
|
||||
addPagination(octokit)
|
||||
|
|
Loading…
Reference in New Issue