diff --git a/auth.js b/auth.js index 0fab008..552072f 100644 --- a/auth.js +++ b/auth.js @@ -1,4 +1,14 @@ -const request = require('request-promise'); +const { requestWithRetries, isRequestError, isStatusCodeError } = require('./requestPromiseUtils'); + +const shouldRetry = (err, nextTryCount) => { + if (nextTryCount > 5) { + return false; + } + + return isRequestError(err) || (isStatusCodeError(err) && (err.statusCode === 403)); +}; + +const computeRetryDelay = (err, nextTryCount) => (Math.round(Math.random() * 100) + (nextTryCount * 750)); module.exports = (zuoraClient) => { let accessToken; @@ -22,7 +32,10 @@ module.exports = (zuoraClient) => { json: true, }; - const response = await request(options); + const response = await requestWithRetries(options, shouldRetry, computeRetryDelay); + if (!response) { + throw new Error('ZuoraJS: Auth: Empty Response'); + } accessToken = response.access_token; renewalTime = Date.now() + ((response.expires_in * 1000) - 60000); diff --git a/requestPromiseUtils.js b/requestPromiseUtils.js new file mode 100644 index 0000000..28fb39f --- /dev/null +++ b/requestPromiseUtils.js @@ -0,0 +1,34 @@ +const requestPromise = require('request-promise'); +const requestPromiseErrors = require('request-promise/errors'); + +const requestWithRetries = async (requestOptions, shouldRetry, computeRetryDelay) => { + const makeRequest = async (tryCount) => { + let response; + try { + response = await requestPromise(requestOptions); + } catch (err) { + if (!shouldRetry || !shouldRetry(err, tryCount)) { + throw err; + } + + const nextTryCount = tryCount + 1; + const retryDelay = await ((computeRetryDelay && computeRetryDelay(err, nextTryCount)) || 1000); + await new Promise((resolve) => setTimeout(resolve, retryDelay)); + + response = makeRequest(nextTryCount); + } + + return response; + }; + + return makeRequest(1); +}; + +const isRequestError = (err) => (err instanceof requestPromiseErrors.RequestError); +const isStatusCodeError = (err) => (err instanceof requestPromiseErrors.StatusCodeError); + +module.exports = { + requestWithRetries, + isRequestError, + isStatusCodeError, +};