I have a wrapper that calls an async function:
function fetchAPI(arg1: number, arg2: number, arg3: string) {
return new Promise((resolve, reject) => {
try {
myFetchFunction(arg1, arg2, arg3).then((r: any) => {
if (!r) {
reject("Error 01")
}
resolve(r)
})
} catch {
reject("Error 01")
}
})
}
Since the API I am querying is quite unstable, it occurs frequently that the fetchAPI
function rejects.
Because of this, I make another function that calls fetchAPI
, if it rejects it will repeat the call at most 3 times (waiting 1s) and if it fails all the times it will just resolve with undefined
. While if it goes through any of the 3 times, it will simply resolve with the correct response.
function fetchAPIRepeat(arg1: number, arg2: number, arg3: string, n: number = 0) {
return new Promise((resolve) => {
fetchAPI(arg1, arg2, arg3).then((r) => {
resolve(r)
}).catch(() => {
if(n < 3) {
console.log("Partial error: " n)
sleep(1000).then(() => {
resolve(fetchAPIRepeat(arg1, arg2, arg3, n 1))
})
} else {
resolve(undefined)
}
})
})
}
This works perfectly fine. However, I would like to create a 'general wrapper' which would operate as the fetchAPIRepeat
function, but for any promise function I pass it through.
This is what I have tried, however it doesn't work:
function promiseRepeatWrapper(fn: (...args: any[]) => Promise<any>, n: number = 0, ...args: any[]) {
return new Promise((resolve) => {
fn(args).then((r) => {
resolve(r)
}).catch(() => {
if(n < 3) {
console.log("Partial error: " n)
sleep(1000).then(() => {
resolve(this.errorWrapper(fn, n 1, args))
})
} else {
resolve(undefined)
}
})
})
}
By 'doesn't work' I mean that the console logs the 'Partial error' for three times, and then resolves with undefined, despite being sure that the promise goes through correctly all three of the times:
Partial error: 0
Partial error: 1
Partial error: 2
Other than helping me fix the function, I am also interested in error-handling design improvements for my promise-repeat pattern.
Thanks.
CodePudding user response:
This can be achieved with async/await. You do not need to pass that args again. You can do it will a lot more generic approach. Where you can pass who many times to retry, and how much to wait after retry
Here is a typescript playgorund
const waitFor = (timeout: number): Promise<void> => {
return new Promise((resolve) => {
setTimeout(() => resolve(), timeout);
});
}
async function retryPromise<T>(fn: () => Promise<T>, repeat = 3, retryAfter = 1000): Promise<T> {
let currentAttpmt = 1;
while(currentAttpmt <= 3) {
try {
return await fn();
} catch (e) {
currentAttpmt = 1;
await waitFor(retryAfter);
}
}
//it failed 3 times in a row
throw new Error("Cannot do this");
}