Skip to content

Commit 0737cad

Browse files
committed
make frontend api calls that fail due to server being gone auto-retry a little bit
1 parent 4d5a379 commit 0737cad

File tree

1 file changed

+30
-3
lines changed
  • src/packages/frontend/client

1 file changed

+30
-3
lines changed

src/packages/frontend/client/api.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ This doesn't know anything about types, etc.
1111

1212
import { join } from "path";
1313
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
14+
import { delay } from "awaiting";
15+
import { trunc } from "@cocalc/util/misc";
1416

1517
export default async function api(endpoint: string, args?: object) {
1618
return await callApi(join("v2", endpoint), args);
@@ -21,9 +23,24 @@ export async function v1(endpoint: string, args?: object) {
2123
return await callApi(join("v1", endpoint), args);
2224
}
2325

26+
// if api call fails (typically 5xx due to a temporary restart of
27+
// backend servers e.g., in kubernetes) we wait RETRY_DELAY_MS, then give
28+
// it NUM_RETRIES many ties before showing the user an error.
29+
// Setting the third numRetriesOnFail argument to 0 below
30+
// can be used to disable this behavior.
31+
// This "api call fails" isn't where you get an error json
32+
// back, but when actually making the request really is
33+
// failing, e.g., due to network or server issues.
34+
const RETRY_DELAY_MS = 2000;
35+
const NUM_RETRIES = 3;
36+
2437
// NOTE: I made this complicated with respClone, so I can see
2538
// what the response is if it is not JSON.
26-
async function callApi(endpoint: string, args?: object) {
39+
async function callApi(
40+
endpoint: string,
41+
args?: object,
42+
numRetriesOnFail?: number,
43+
) {
2744
const url = join(appBasePath, "api", endpoint);
2845
const resp = await fetch(url, {
2946
method: "POST",
@@ -38,9 +55,19 @@ async function callApi(endpoint: string, args?: object) {
3855
json = await resp.json();
3956
} catch (e) {
4057
console.log(e);
41-
console.log(await respClone.text());
42-
throw Error("API server is down -- try again later");
58+
const r = await respClone.text();
59+
console.log(trunc(r, 2000));
60+
if (numRetriesOnFail != null && numRetriesOnFail == 0) {
61+
throw Error("API server is down -- try again later");
62+
}
63+
numRetriesOnFail = numRetriesOnFail ?? NUM_RETRIES;
64+
console.log(
65+
`waiting 3s then trying again up to ${numRetriesOnFail} more times`,
66+
);
67+
await delay(RETRY_DELAY_MS);
68+
return await callApi(endpoint, args, numRetriesOnFail - 1);
4369
}
70+
console.log("json = ", json);
4471
if (json == null) {
4572
throw Error("timeout -- try again later");
4673
}

0 commit comments

Comments
 (0)