-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathinRequestCache.ts
More file actions
71 lines (64 loc) · 1.73 KB
/
inRequestCache.ts
File metadata and controls
71 lines (64 loc) · 1.73 KB
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
// This is a cache that is updated as part of the request/response cycle.
// This is useful in serverless runtimes where `setTimeout` doesn't exist or does something useless.
import { Logger } from "./types";
export default function inRequestCache<T>(
ttl: number,
logger: Logger | undefined,
fn: () => Promise<T | undefined>,
) {
let value: T | undefined = undefined;
let lastFetch = 0;
let fetching: Promise<void> | null = null;
async function refresh(): Promise<T | undefined> {
if (!fetching) {
fetching = (async () => {
try {
const result = await fn();
logger?.debug("inRequestCache: fetched value", result);
if (result !== undefined) {
value = result;
}
} catch (err) {
if (logger) {
logger.error?.("inRequestCache: error refreshing value", err);
}
} finally {
lastFetch = Date.now();
fetching = null;
}
})();
}
await fetching;
return value;
}
const waitRefresh = async () => {
if (fetching) await fetching;
};
const destroy = () => {
fetching = null;
value = undefined;
lastFetch = 0;
};
return {
get(): T | undefined {
const now = Date.now();
// If value is undefined, just return undefined
if (value === undefined) {
return undefined;
}
// If value is stale, trigger background refresh
if (now - lastFetch > ttl) {
logger?.debug(
"inRequestCache: stale value, triggering background refresh",
);
void refresh();
}
return value;
},
async refresh(): Promise<T | undefined> {
return await refresh();
},
waitRefresh,
destroy,
};
}