Created
January 17, 2025 21:12
-
-
Save kevboutin/a53dcbba6d85903c07bd500a6e12bd20 to your computer and use it in GitHub Desktop.
Provides an exponentially backoff retry mechanism
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Provides a class for managing retry operations. | |
* @class | |
*/ | |
module.exports = class ExponentialBackoffRetry { | |
/** | |
* Constructor. | |
* | |
* @param {Object} [options] The options. | |
* @param {number} [options.baseDelay] The base delay in milliseconds. Defaults to 1000. | |
* @param {number} [options.maxDelay] The maximum delay in milliseconds. Defaults to 30000. | |
* @param {number} [options.maxRetries] The maximum number of retries. Defaults to 5. | |
* @param {boolean} [options.jitter] When true, prevents a thundering herd issue. Defaults to true. | |
*/ | |
constructor(options = {}) { | |
this.baseDelay = options.baseDelay || 1000; | |
this.maxDelay = options.maxDelay || 30000; | |
this.maxRetries = options.maxRetries || 5; | |
this.jitter = options.jitter || true; | |
} | |
/** | |
* Calculate the time delay based on the number of retry attempts. | |
* | |
* @param {number} retryCount The number of retries. | |
* @returns {number} The delay in milliseconds. | |
*/ | |
calculateDelay(retryCount) { | |
// Calculate exponential delay: 2^retryCount * baseDelay | |
let delay = Math.min(this.maxDelay, Math.pow(2, retryCount) * this.baseDelay); | |
// Add jitter to prevent thundering herd problem. | |
if (this.jitter) { | |
delay = delay * (0.5 + Math.random()); | |
} | |
return delay; | |
} | |
/** | |
* Wait a specified time period. | |
* | |
* @param {number} ms Milliseconds. | |
* @returns {Promise} A Promise to wait in milliseconds given. | |
*/ | |
wait(ms) { | |
return new Promise((resolve) => setTimeout(resolve, ms)); | |
} | |
/** | |
* Execute the function with retries in the event of failure. | |
* | |
* @param {Function} fn The function to execute. | |
* @returns {Promise} A Promise to return after function execution. | |
*/ | |
async execute(fn) { | |
let retries = 0; | |
while (true) { | |
try { | |
return await fn(); | |
} catch (error) { | |
if (retries >= this.maxRetries) { | |
throw new Error(`Failed after ${retries} retries: ${error.message}`); | |
} | |
const delay = this.calculateDelay(retries); | |
await this.wait(delay); | |
retries++; | |
} | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment