If you're getting an error in the logs, but it's not going into your .catch()
handler, then the only explanation for that is that whatever fn()
you're calling is not returning a promise that gets rejected when that error happens. So, further debugging on that specific issue would need to take place in the specific fn
function that causes this problem.
The specific 429 error is a rate limiting type error where you're likely making too many requests too quickly. Given your code, this could easily happen if the request fails for some persistent reason, so banging on it over and over with retry requests just continues to fail the same way until eventually the target host says you're making too many requests too quickly.
Nearly all production-quality retry systems that are going to do many consecutive retries will implement a timer backoff (each request waiting longer than the previous one before trying) so you don't just hammer retry requests one after another rapid fire. Instead, you provide the host some time to recover or perhaps remedy whatever the issue is that's causing the error and hopefully also avoid rate limiting restrictions. Having any client do rapid fire retries with no backoff is a recipe for what's known as an avalanche failure on the host. An avalanche failure is where one small problem on the server causes lots of clients to go into massive retry loops just hammering the host so hard that it can't handle all the incoming requests and can't recover from whatever the original problem was. An appropriate backoff in the client prevents this. Hosts may also try to protect themselves with rate limiting (which you are perhaps running into). There is also no benefit to you repeating the same request over and over faster than the target host's rate limit.
Then, lastly, you can clean up your code by removing the new Promise()
as you can just chain promises from successive calls and return that promise chain. Here's an implementation with that cleanup and a simple backoff algorithm.
function delay(t) {
return new Promise(resolve => setTimeout(resolve, t));
}
const kMinRetryTime = 100;
const kPerRetryAdditionalTime = 500;
function calcBackoff(retries) {
return Math.max(kMinRetryTime, (retries - 1) * kPerRetryAdditionalTime);
}
export function retry(fn: Function, params: any, times = 1e9 + 7) {
let retries = 0;
function attempt() {
return fn(params).catch((err: Error) => {
++retries;
console.log(err);
if (retries <= times) {
// still more retries left
return delay(calcBackoff(retries)).then(attempt);
} else {
// bail with error
throw err;
}
})
}
return attempt();
}