Skip to content

Commit

Permalink
Expand retry to also retry rejections
Browse files Browse the repository at this point in the history
  • Loading branch information
ultraq committed Mar 10, 2021
1 parent f47c67f commit 0de520e
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 26 deletions.
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,26 @@ padding time has elapsed.

### retry(doPromise, numRetries, shouldRetry)

Retry a promise a specified number of times. Returns a promise that is
resolved/rejected with the results of the underlying promise, or eventually
rejected after the number of retries has been reached without success.
Retry a promise a specified number of times. A promise that will eventually
resolve to the value from the retried promise, is rejected with the error from
the retried promise, or is rejected with an error message with "Maximum number
of retries reached".

- **doPromise**: A function which returns the promise to be retried.
- **numRetries**: The number of times a retry should be attempted.
- **shouldRetry**: When the promise succeeds, this function is called with the
result to determine whether or not the promise should be retried.
- **numRetries**: The number of times the promise should be retried.
- **shouldRetry**: A function called with 2 parameters, the result from a
promise resolution and the error from a promise rejection (only 1 will be set
each call, depending on whether the promise was resolved/rejected), that
should determine whether or not the promise should be retried. eg:

```javascript
// Retry if a resolved promise result is still in a waiting state
function shouldRetry(result, error) {
return result && result.waiting;
}

// Retry a rejected promise
function shouldRetry(result, error) {
return !!error;
}
```
62 changes: 42 additions & 20 deletions promise-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,35 +55,57 @@ export function pad(doPromise, padMs) {
* @param {Function} doPromise
* A function which returns the promise to be retried.
* @param {Number} numRetries
* The number of times a retry should be attempted.
* The number of times the promise should be retried.
* @param {Function} shouldRetry
* When the promise succeeds, this function is called with the result to
* determine whether or not the promise should be retried.
* A function called with 2 parameters, the result from a promise resolution
* and the error from a promise rejection (only 1 will be set each call,
* depending on whether the promise was resolved/rejected), that should
* determine whether or not the promise should be retried. eg:
* ```javascript
* // Retry if a resolved promise result is still in a `waiting` state
* function shouldRetry(result, error) {
* return result && result.waiting;
* }
* // Retry a rejected promise
* function shouldRetry(result, error) {
* return !!error;
* }
* ```
* @return {Promise}
* If the promise succeeds and we don't have to retry, then the promise will
* be resolved with the result. If the promise itself returns an error or the
* number of retries has been exceeded, it will be rejected.
* A promise that will eventually resolve to the value from the retried
* promise, is rejected with the error from the retried promise, or is
* rejected with an error message with "Maximum number of retries reached".
*/
export function retry(doPromise, numRetries, shouldRetry) {
let retries = 0;
return new Promise((resolve, reject) => {
function retryIfNeeded(response, error) {
if (shouldRetry(response, error)) {
if (retries < numRetries) {
retries++;
return makeAttempt();
}
else {
reject(new Error('Maximum number of retries reached'));
}
}
else if (response) {
resolve(response);
}
else {
reject(error);
}
}
function makeAttempt() {
return doPromise()
.then(response => {
if (shouldRetry(response)) {
if (retries < numRetries) {
retries++;
return makeAttempt();
}
else {
reject(new Error('Maximum number of retries reached'));
}
}
else {
resolve(response);
.then(
response => {
return retryIfNeeded(response, undefined);
},
error => {
return retryIfNeeded(undefined, error);
}
})
.catch(reject);
);
}
makeAttempt();
});
Expand Down

0 comments on commit 0de520e

Please sign in to comment.