Last active
September 16, 2023 02:43
-
-
Save domenic/2936696 to your computer and use it in GitHub Desktop.
Generalized promise retryer
This file contains 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
"use strict"; | |
// `f` is assumed to sporadically fail with `TemporaryNetworkError` instances. | |
// If one of those happens, we want to retry until it doesn't. | |
// If `f` fails with something else, then we should re-throw: we don't know how to handle that, and it's a | |
// sign something went wrong. Since `f` is a good promise-returning function, it only ever fulfills or rejects; | |
// it has no synchronous behavior (e.g. throwing). | |
function dontGiveUp(f) { | |
return f().then( | |
undefined, // pass through success | |
function (err) { | |
if (err instanceof TemporaryNetworkError) { | |
return dontGiveUp(f); // recurse | |
} | |
throw err; // rethrow | |
} | |
}); | |
} | |
// Analogous synchronous code: | |
function dontGiveUpSync(fSync) { | |
try { | |
return fSync(); | |
} catch (err) { | |
if (err instanceof TemporaryNetworkError) { | |
return dontGiveUpSync(fSync); | |
} | |
throw err; | |
} | |
} | |
// Note how we created this powerful abstraction without ever using ANY aspect of the promise implementation | |
// besides the Promises/A "thenable"-ness. In particular, we had NO need of a deferred library, and we can | |
// interoperate with ANY promise library, returning to the caller the same type of promise we received (i.e. | |
// we don't assimilate When.js promises into Q promises in order to work with them). | |
// An example of a library that makes extensive use of this property is | |
// https://github.com/domenic/chai-as-promised/ | |
// Unfortunately such composable patterns are impossible with jQuery promises, since there is no way to trap | |
// and rethrow errors. jQuery only allows you to catch explicit rejections, but does not allow access to | |
// thrown exceptions, and furthermore you cannot transition into a rejected state by (re)throwing or out | |
// of one by choosing not to rethrow: in a jQuery promise's fulfilled and rejected callbacks, you need to | |
// manually use jQuery's deferred library to transition state. |
I took a stab at this
Working version with delay and try count limit:
function retry(func, count = 5, delay = 1000) {
return func().then(undefined, (e) => {
if (count - 1) {
return new Promise((resolve) => setTimeout(resolve, delay)).then(() =>
retry(func, count - 1, delay)
);
}
throw e;
});
};
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I find myself needing this type of solution a lot, i wonder if theres anything that supports