I see a lot of answers and none of them work for me. I am implementing retry code in the browser, where if the API hasn't responded in 4000ms it retries.
The problem is I want to do this for POST requests that are not idempotent, and the response state in chrome dev tools (whether it succeeds or fails) does NOT match axios or my implemented logic of when a timeout occurs.
This results in POST requests calling twice successfully on the server even though the connection throws an error within my axios code. It's a race condition somewhere, I'm assuming the time between axios connects and when it is able to set the result of the response.
I've tried default axios timeout which doesn't work, as that is a response timeout.
I've also tried to implement a connection timeout and I still am encountering the same issue.
The issue starts occuring if I set the connTimeout to be right in the ballpark of how long it takes the server to response on average, +/- a few ms. I feel like when a request is cancelled, somehow it's not checking if the connection actually succeeded or not before attempting to cancel.
I'd do it myself (before calling source.cancel(), but I'm not sure what I can read to get the state. The only thing I see there is an unresolved promise)
const makeRequest = async (args, connTimeout, responseTimeout) => {
const source = axios.CancelToken.source();
const argsWithToken = {
...args,
cancelToken: source.token,
};
const api = buildAxios(responseTimeout);
const timeout = setTimeout(source.cancel, connTimeout);
return api(argsWithToken).then(result => {
clearTimeout(timeout);
return result;
});
};
const handleRetries = (args, maxRetries) => (
new Promise(async (resolve, reject) => { /* eslint-disable-line */
let retries = 0;
let success = false;
while (!success && retries < maxRetries) {
try {
const result = await makeRequest(args, 300, 30000); /* eslint-disable-line */
success = true;
resolve(result);
} catch (err) {
retries += 1;
// console.log(`Error making ${args.method} request to ${args.url}, retrying... #${retries}`);
}
}
// line below is included to prevent process leaks
if (!success) reject(new Error(`Retried ${retries} times and still failed: ${args.url}`));
})
);
handleRetries({url: '/settings', method: 'get'}, 3)