diff --git a/lib/github-auth.js b/lib/github-auth.js index c492fcd182474c..ea09cfe7989fdd 100644 --- a/lib/github-auth.js +++ b/lib/github-auth.js @@ -124,6 +124,7 @@ function sendTokenToAllServers(token) { // Track rate limit requests remaining. +// Ideally, we would want priority queues here. var reqRemaining = new Map(); // From token to requests remaining. var reqReset = new Map(); // From token to timestamp. @@ -146,22 +147,44 @@ function utcEpochSeconds() { var userTokenRateLimit = 12500; +// Return false if the token cannot reasonably be expected to perform +// a GitHub request. +function isTokenUsable(token, now) { + var reqs = reqRemaining.get(token); + var reset = reqReset.get(token); + // We don't want to empty more than 3/4 of a user's rate limit. + var hasRemainingReqs = reqs > (userTokenRateLimit / 4); + var isBeyondRateLimitReset = reset < now; + return hasRemainingReqs || isBeyondRateLimitReset; +} + +// Return a list of tokens (as strings) which can be used for a GitHub request, +// with a reasonable chance that the request will succeed. +function usableTokens() { + var now = utcEpochSeconds(); + return githubUserTokens.data.filter(function(token) { + return isTokenUsable(token, now); + }); +} + // Retrieve a user token if there is one for which we believe there are requests // remaining. Return undefined if we could not find one. function getReqRemainingToken() { // Go through the user tokens. - // Keep the first one which is usable or has reset. - var now = utcEpochSeconds(); - for (var token of reqReset.keys()) { + // Among usable ones, use the one with the highest number of remaining + // requests. + var tokens = usableTokens(); + var highestReq = -1; + var highestToken; + for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; var reqs = reqRemaining.get(token); - var reset = reqReset.get(token); - // We don't want to empty more than 3/4 of a user's rate limit. - var hasRemainingReqs = reqs > (userTokenRateLimit / 4); - var isBeyondRateLimitReset = reset < now; - if (hasRemainingReqs || isBeyondRateLimitReset) { - return token; + if (reqs > highestReq) { + highestReq = reqs; + highestToken = token; } } + return highestToken; } function addGithubToken(token) {