-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy pathfetchCache.ts
84 lines (71 loc) · 1.95 KB
/
fetchCache.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* For some reason we sometimes see errors fetching from our registry, because
* of that we retry the fetches
*
* The error was:
*
* Client network socket disconnected before secure TLS connection was established
*/
async function fetchRetry(url: string, opts: RequestInit & {retry?: number}) {
let retry = opts?.retry ?? 1;
while (retry > 0) {
try {
return await fetch(url, opts);
} catch (e) {
if (retry !== 0) {
// eslint-disable-next-line no-console
console.warn(`failed to fetch \`${url}\`. Retrying for ${retry} more times`);
retry = retry - 1;
continue;
}
throw e;
}
}
return null;
}
interface Options {
/**
* URL to fetch the data from
*/
dataUrl: string;
/**
* The name of the registry, used for logging messages
*/
name: string;
}
/**
* Creates a `ensureData` function that fetches from a URL only once. Subsequent
* calls will used the already fetched data.
*/
export function makeFetchCache<DataType>({dataUrl, name}: Options) {
let activeFetch: Promise<any> | null = null;
let data: DataType | null = null;
async function ensureData() {
if (data) {
return data;
}
async function fetchData() {
try {
// eslint-disable-next-line no-console
console.log(`Fetching registry ${name} (${dataUrl})`);
const result = await fetchRetry(dataUrl, {retry: 5});
data = await result?.json();
// eslint-disable-next-line no-console
console.log(`Got data for registry ${name} (${dataUrl})`);
} catch (err) {
// eslint-disable-next-line no-console
console.error(`Unable to fetch for ${name}: ${err.message}`);
data = null;
throw err;
}
activeFetch = null;
}
// If we're not already making a request do so now
if (activeFetch === null) {
activeFetch = fetchData();
}
await activeFetch;
return data;
}
return ensureData;
}