When is it safe to retry a call?
My check-in app is used in places where the signal is not always good. On a network error I did not want the door staff to keep tapping again and again, so the app retries by itself. But there is one rule I must not break: I only retry calls whose repetition cannot do harm.
What counts as a network error?
If there is no response, I cannot know whether the server received the request. Maybe it did not, and maybe it did, and the response just never made it back. So for me a network error is only the case where no response arrived at all. If the server answered, whether with a 4xx or a 5xx, that is not a network error, and I do not retry it.
/** No response at all = network failure (offline, timeout). A 4xx/5xx reply is not. */
function isNetworkError(error: unknown): boolean {
return axios.isAxiosError(error) && !error.response;
}
/**
* Retries a call once on a network failure. ONLY use it for calls that are
* safe to repeat: reads, or writes that are idempotent on the server.
*/
async function withNetworkRetry<T>(call: () => Promise<T>, retries = 1): Promise<T> {
try {
return await call();
} catch (error) {
if (retries > 0 && isNetworkError(error)) {
await new Promise((resolve) => setTimeout(resolve, 700));
return withNetworkRetry(call, retries - 1);
}
throw error;
}
}
An excerpt of real code, anonymised.
Writes are the danger
A read call can be repeated. A check-in cannot necessarily: if the first request went through but the response was lost, the second request would admit someone twice. So I only use retries for reads, or for writes that are idempotent on the server.
Idempotent means that sending the same request twice gives the same result as sending it once. That has to be solved on the server, the client cannot guarantee it.
Before a retry there is a short wait, 700 milliseconds in my case, and I only retry once. Door staff need a quick answer, not a long wait.
Working on a similar problem?
If you are stuck, or want a second look at your solution, write to me. I am happy to look.
Write to me →