@nifrajs/cache 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +144 -14
- package/dist/cache.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/memory-cache.d.ts +9 -0
- package/dist/memory-cache.d.ts.map +1 -1
- package/dist/memory-cache.js +47 -0
- package/dist/memory-cache.js.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cache.ts +164 -27
- package/src/index.ts +1 -0
- package/src/memory-cache.ts +45 -0
- package/src/types.ts +27 -0
package/README.md
CHANGED
|
@@ -31,7 +31,12 @@ await cache.invalidateTag(`user:${id}`)
|
|
|
31
31
|
**immediately** while a **background** refresh runs (deduped). Latency stays flat; data self-heals.
|
|
32
32
|
- **Miss/expired**: awaits `loader`. Concurrent misses for the same key share **one** call (no stampede).
|
|
33
33
|
- A throwing `loader` is **not** cached (and in the background path goes to `onError`, never rejects the caller).
|
|
34
|
-
-
|
|
34
|
+
- **Store outage**: a store `get` that throws or rejects is a miss, so the loader answers; a `set` that
|
|
35
|
+
fails still returns the loaded value, and a `fence` that fails leaves that load uncached. Each
|
|
36
|
+
failure goes to `onStoreError(error, { op })`, which by default logs one line per operation per
|
|
37
|
+
minute without the key. The explicit `get`, `set`, `delete`, `invalidateTag` and `clear` still
|
|
38
|
+
reject, so a failed invalidation is never silent.
|
|
39
|
+
- **`set` / `get` / `has` / `delete`**, **`invalidateTag(tag)`**, **`clear()`**. A `delete`, `invalidateTag`, `clear` or newer `set` also stops a `wrap` load or background refresh already running for that key or tag from storing its result, and the next `wrap` loads afresh. A `delete`, `invalidateTag` or `clear` runs after this cache's own async store writes it covers, so a store that applies requests out of order cannot land one after it.
|
|
35
40
|
- TTL: `ttlMs` (→ stale) + optional `swrMs` (→ served-stale window) + optional `tags`.
|
|
36
41
|
|
|
37
42
|
## Stores
|
|
@@ -45,6 +50,14 @@ opt-in. For a cache shared across instances, implement `CacheStore`
|
|
|
45
50
|
const cache = createCache({ store: new RedisCacheStore(redis) })
|
|
46
51
|
```
|
|
47
52
|
|
|
53
|
+
A store several caches or processes share should also implement the optional `fence(key, tags)` and
|
|
54
|
+
`setIfFence(key, entry, tags, token)`. A `wrap` load takes a fence before it runs and stores its result
|
|
55
|
+
through `setIfFence`, which must refuse, in one atomic step, when a `set` or `delete` of the key, an
|
|
56
|
+
`invalidateTag` of one of its tags, or a `clear` ran since that fence, from any cache. Without them, a
|
|
57
|
+
load running in one process can store a value another process invalidated meanwhile. `MemoryCache`
|
|
58
|
+
implements both, and `cacheStoreCertificationProfile({ fencing: true })` from
|
|
59
|
+
`@nifrajs/testing/certification` checks a store's implementation.
|
|
60
|
+
|
|
48
61
|
On **Cloudflare Workers** the in-memory cache is per-isolate and short-lived - back it with **CF KV** (or
|
|
49
62
|
the Cache API) via a `CacheStore` for anything that should survive across requests/instances.
|
|
50
63
|
|
|
@@ -52,7 +65,8 @@ the Cache API) via a `CacheStore` for anything that should survive across reques
|
|
|
52
65
|
|
|
53
66
|
`observer` receives one event per operation after it settles: `{ op, outcome, startedAt, durationMs,
|
|
54
67
|
key, tag, tagCount, context }`. `outcome` is `hit`, `stale` or `miss` for reads, `ok` for writes and a
|
|
55
|
-
finished background refresh (`op: "revalidate"`), `error` when the store or loader threw.
|
|
68
|
+
finished background refresh (`op: "revalidate"`), `error` when the store or loader threw. A `wrap`
|
|
69
|
+
that loaded through a store outage reports `miss`. An observer
|
|
56
70
|
that throws is swallowed; it never changes a result. Without an observer the cache reads no extra clock.
|
|
57
71
|
|
|
58
72
|
`cache.for(c)` binds a request (or job) context, and every event carries it. That is how
|
|
@@ -75,7 +89,7 @@ whenever it is set.
|
|
|
75
89
|
|
|
76
90
|
## API
|
|
77
91
|
|
|
78
|
-
- `createCache(options?)` → `Cache` - `{ store?, defaultTtlMs?, now?, onError?, observer?, beacon?, capabilities? }`.
|
|
92
|
+
- `createCache(options?)` → `Cache` - `{ store?, defaultTtlMs?, now?, onError?, onStoreError?, observer?, beacon?, capabilities? }`.
|
|
79
93
|
- `cache.wrap(key, loader, { ttlMs?, swrMs?, tags? })` · `get` · `has` · `set` · `delete` · `invalidateTag` · `clear`.
|
|
80
94
|
- `cache.for(context)` → the same surface bound to a request or job context.
|
|
81
95
|
- `MemoryCache({ maxEntries?, now? })` - the default store; implement `CacheStore` for your own.
|
package/dist/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,KAAK,EAIL,YAAY,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,KAAK,EAIL,YAAY,EAOb,MAAM,YAAY,CAAA;AAmDnB,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,OAAO,GAAE,YAAiB,GAAG,KAAK,CAyW7D"}
|
package/dist/cache.js
CHANGED
|
@@ -16,6 +16,16 @@ function assertDuration(value, name) {
|
|
|
16
16
|
throw new RangeError(`[nifra/cache] ${name} must be a finite non-negative number`);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
const STORE_REPORT_INTERVAL_MS = 60_000;
|
|
20
|
+
const STORE_REPORT_DETAIL_CHARS = 200;
|
|
21
|
+
/** The error's own words with the key cut out, since a store may name the key it failed on. */
|
|
22
|
+
function storeErrorDetail(error, key) {
|
|
23
|
+
const text = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
24
|
+
const redacted = key === "" ? text : text.split(key).join("<key>");
|
|
25
|
+
return redacted.length > STORE_REPORT_DETAIL_CHARS
|
|
26
|
+
? `${redacted.slice(0, STORE_REPORT_DETAIL_CHARS)}...`
|
|
27
|
+
: redacted;
|
|
28
|
+
}
|
|
19
29
|
function notify(observer, event) {
|
|
20
30
|
try {
|
|
21
31
|
const result = observer(event);
|
|
@@ -47,9 +57,62 @@ export function createCache(options = {}) {
|
|
|
47
57
|
const store = options.store ?? new MemoryCache({ now });
|
|
48
58
|
const onError = options.onError ??
|
|
49
59
|
((error, key) => console.error(`[nifra/cache] revalidate ${JSON.stringify(key)} failed:`, error));
|
|
60
|
+
const lastStoreReport = new Map();
|
|
61
|
+
const reportStoreError = (op, key, error) => {
|
|
62
|
+
try {
|
|
63
|
+
if (options.onStoreError !== undefined) {
|
|
64
|
+
options.onStoreError(error, { op });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const last = lastStoreReport.get(op);
|
|
68
|
+
const at = now();
|
|
69
|
+
if (last !== undefined && at - last < STORE_REPORT_INTERVAL_MS)
|
|
70
|
+
return;
|
|
71
|
+
lastStoreReport.set(op, at);
|
|
72
|
+
console.error(`[nifra/cache] store ${op} failed; loading without the cache (${storeErrorDetail(error, key)})`);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// A failing reporter must not turn a loaded value into an error.
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/** `wrap`'s read: a store that throws or rejects is a miss, so the loader answers. */
|
|
79
|
+
const readEntry = async (key) => {
|
|
80
|
+
try {
|
|
81
|
+
return await store.get(key);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
reportStoreError("get", key, error);
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
50
88
|
const observer = options.observer;
|
|
51
89
|
// Single-flight: concurrent loads for the same key share one promise (miss stampede + SWR dedup).
|
|
90
|
+
// A delete, tag invalidation, clear or newer set withdraws a load's right to store its result, so
|
|
91
|
+
// a refresh that started before the invalidation cannot write the old value back. A store with
|
|
92
|
+
// `fence`/`setIfFence` also refuses a load's write after such a change from another cache sharing
|
|
93
|
+
// it, and a delete, invalidation or clear waits for this cache's async writes it covers, so a store
|
|
94
|
+
// that applies requests out of order cannot land one of them after it.
|
|
52
95
|
const inflight = new Map();
|
|
96
|
+
const withdraw = (matches) => {
|
|
97
|
+
for (const [key, flight] of inflight) {
|
|
98
|
+
if (!matches(key, flight.tags))
|
|
99
|
+
continue;
|
|
100
|
+
flight.withdraw();
|
|
101
|
+
inflight.delete(key);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const fencing = typeof store.fence === "function" && typeof store.setIfFence === "function";
|
|
105
|
+
const writing = new Set();
|
|
106
|
+
// Run a delete, invalidation or clear after every async write it covers has settled.
|
|
107
|
+
const after = (matches, change) => {
|
|
108
|
+
const covered = [];
|
|
109
|
+
for (const write of writing)
|
|
110
|
+
if (matches(write.key, write.tags))
|
|
111
|
+
covered.push(write.done);
|
|
112
|
+
if (covered.length === 0)
|
|
113
|
+
return Promise.resolve(change());
|
|
114
|
+
return Promise.allSettled(covered).then(change);
|
|
115
|
+
};
|
|
53
116
|
async function get(key) {
|
|
54
117
|
const entry = await store.get(key);
|
|
55
118
|
return entry === undefined ? undefined : entry.value;
|
|
@@ -57,27 +120,94 @@ export function createCache(options = {}) {
|
|
|
57
120
|
async function has(key) {
|
|
58
121
|
return (await store.get(key)) !== undefined;
|
|
59
122
|
}
|
|
60
|
-
|
|
123
|
+
function entryOf(value, opts) {
|
|
61
124
|
const ttlMs = opts.ttlMs ?? defaultTtlMs;
|
|
62
125
|
const swrMs = opts.swrMs ?? 0;
|
|
63
126
|
assertDuration(ttlMs, "ttlMs");
|
|
64
127
|
assertDuration(swrMs, "swrMs");
|
|
65
128
|
const t = now();
|
|
66
|
-
|
|
129
|
+
return { value, staleAt: t + ttlMs, expiresAt: t + ttlMs + swrMs };
|
|
130
|
+
}
|
|
131
|
+
async function put(key, entry, tags, fenced) {
|
|
132
|
+
const pending = fenced !== undefined && store.setIfFence !== undefined
|
|
133
|
+
? store.setIfFence(key, entry, tags, fenced.token)
|
|
134
|
+
: store.set(key, entry, tags);
|
|
135
|
+
if (!(pending instanceof Promise))
|
|
136
|
+
return;
|
|
137
|
+
const record = { key, tags, done: pending };
|
|
138
|
+
writing.add(record);
|
|
139
|
+
try {
|
|
140
|
+
await pending;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
writing.delete(record);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
async function write(key, value, opts) {
|
|
147
|
+
await put(key, entryOf(value, opts), opts.tags ?? []);
|
|
148
|
+
}
|
|
149
|
+
function set(key, value, opts = {}) {
|
|
150
|
+
withdraw((flightKey) => flightKey === key);
|
|
151
|
+
return write(key, value, opts);
|
|
152
|
+
}
|
|
153
|
+
function remove(key) {
|
|
154
|
+
const matches = (writeKey) => writeKey === key;
|
|
155
|
+
withdraw(matches);
|
|
156
|
+
return after(matches, () => store.delete(key));
|
|
157
|
+
}
|
|
158
|
+
function invalidateTag(tag) {
|
|
159
|
+
const matches = (_key, tags) => tags.includes(tag);
|
|
160
|
+
withdraw(matches);
|
|
161
|
+
return after(matches, () => store.invalidateTag(tag));
|
|
162
|
+
}
|
|
163
|
+
function clear() {
|
|
164
|
+
withdraw(() => true);
|
|
165
|
+
return after(() => true, () => store.clear());
|
|
67
166
|
}
|
|
68
167
|
function load(key, loader, opts) {
|
|
69
168
|
const existing = inflight.get(key);
|
|
70
169
|
if (existing !== undefined)
|
|
71
|
-
return existing;
|
|
170
|
+
return existing.promise;
|
|
171
|
+
let withdrawn = false;
|
|
72
172
|
const p = (async () => {
|
|
173
|
+
// Taken before the loader runs, so a change from another cache during the load refuses its
|
|
174
|
+
// write. Awaited only when async: a sync store keeps the loader starting synchronously.
|
|
175
|
+
let fenced;
|
|
176
|
+
let storable = true;
|
|
177
|
+
if (fencing) {
|
|
178
|
+
try {
|
|
179
|
+
const token = store.fence?.(key, opts.tags ?? []);
|
|
180
|
+
fenced = { token: token instanceof Promise ? await token : token };
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
// Without a token the write could land after another cache's invalidation: load uncached.
|
|
184
|
+
reportStoreError("fence", key, error);
|
|
185
|
+
storable = false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
73
188
|
const value = await loader();
|
|
74
|
-
|
|
189
|
+
if (!withdrawn && storable) {
|
|
190
|
+
// Built outside the try: a bad ttlMs is the caller's error, not a store outage.
|
|
191
|
+
const entry = entryOf(value, opts);
|
|
192
|
+
try {
|
|
193
|
+
await put(key, entry, opts.tags ?? [], fenced);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
reportStoreError("set", key, error);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
75
199
|
return value;
|
|
76
200
|
})().finally(() => {
|
|
77
|
-
if (inflight.get(key) === p)
|
|
201
|
+
if (inflight.get(key)?.promise === p)
|
|
78
202
|
inflight.delete(key);
|
|
79
203
|
});
|
|
80
|
-
inflight.set(key,
|
|
204
|
+
inflight.set(key, {
|
|
205
|
+
promise: p,
|
|
206
|
+
tags: opts.tags ?? [],
|
|
207
|
+
withdraw: () => {
|
|
208
|
+
withdrawn = true;
|
|
209
|
+
},
|
|
210
|
+
});
|
|
81
211
|
return p;
|
|
82
212
|
}
|
|
83
213
|
function revalidate(key, loader, opts, context) {
|
|
@@ -99,7 +229,7 @@ export function createCache(options = {}) {
|
|
|
99
229
|
});
|
|
100
230
|
}
|
|
101
231
|
async function wrap(key, loader, opts = {}) {
|
|
102
|
-
const entry = await
|
|
232
|
+
const entry = await readEntry(key);
|
|
103
233
|
if (entry !== undefined) {
|
|
104
234
|
if (now() < entry.staleAt)
|
|
105
235
|
return entry.value; // fresh hit
|
|
@@ -146,7 +276,7 @@ export function createCache(options = {}) {
|
|
|
146
276
|
const started = performance.now();
|
|
147
277
|
let outcome = "error";
|
|
148
278
|
try {
|
|
149
|
-
const entry = await
|
|
279
|
+
const entry = await readEntry(key);
|
|
150
280
|
if (entry !== undefined) {
|
|
151
281
|
outcome = readOutcome(entry);
|
|
152
282
|
if (outcome === "stale")
|
|
@@ -163,9 +293,9 @@ export function createCache(options = {}) {
|
|
|
163
293
|
report(observer, "wrap", outcome, started, key, undefined, opts.tags?.length ?? 0, context);
|
|
164
294
|
}
|
|
165
295
|
},
|
|
166
|
-
delete: (key) => settle("delete", key, undefined, 0, () =>
|
|
167
|
-
invalidateTag: (tag) => settle("invalidateTag", undefined, tag, 1, () =>
|
|
168
|
-
clear: () => settle("clear", undefined, undefined, 0,
|
|
296
|
+
delete: (key) => settle("delete", key, undefined, 0, () => remove(key), "ok"),
|
|
297
|
+
invalidateTag: (tag) => settle("invalidateTag", undefined, tag, 1, () => invalidateTag(tag), "ok"),
|
|
298
|
+
clear: () => settle("clear", undefined, undefined, 0, clear, "ok"),
|
|
169
299
|
for: bind,
|
|
170
300
|
};
|
|
171
301
|
}
|
|
@@ -177,9 +307,9 @@ export function createCache(options = {}) {
|
|
|
177
307
|
has,
|
|
178
308
|
set,
|
|
179
309
|
wrap,
|
|
180
|
-
delete:
|
|
181
|
-
invalidateTag
|
|
182
|
-
clear
|
|
310
|
+
delete: remove,
|
|
311
|
+
invalidateTag,
|
|
312
|
+
clear,
|
|
183
313
|
for: bind,
|
|
184
314
|
}
|
|
185
315
|
: observed(observer, undefined);
|
package/dist/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export { createCache } from "./cache.js";
|
|
11
11
|
export { MemoryCache, type MemoryCacheOptions } from "./memory-cache.js";
|
|
12
|
-
export type { Cache, CacheCapabilities, CacheEvent, CacheObserver, CacheOperation, CacheOptions, CacheOutcome, CacheStore, CapabilityBeacon, SetOptions, StoredEntry, WrapOptions, } from "./types.js";
|
|
12
|
+
export type { Cache, CacheCapabilities, CacheEvent, CacheObserver, CacheOperation, CacheOptions, CacheOutcome, CacheStore, CacheStoreOp, CapabilityBeacon, SetOptions, StoredEntry, WrapOptions, } from "./types.js";
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACxE,YAAY,EACV,KAAK,EACL,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACxE,YAAY,EACV,KAAK,EACL,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAA"}
|
package/dist/memory-cache.d.ts
CHANGED
|
@@ -17,14 +17,23 @@ export declare class MemoryCache implements CacheStore {
|
|
|
17
17
|
private expirySweep;
|
|
18
18
|
private readonly maxEntries;
|
|
19
19
|
private readonly now;
|
|
20
|
+
private readonly keyChanges;
|
|
21
|
+
private readonly tagChanges;
|
|
22
|
+
private clearedAt;
|
|
23
|
+
private forgottenAt;
|
|
24
|
+
private epoch;
|
|
20
25
|
constructor(options?: MemoryCacheOptions);
|
|
21
26
|
get(key: string): StoredEntry | undefined;
|
|
22
27
|
set(key: string, entry: StoredEntry, tags: readonly string[]): void;
|
|
23
28
|
delete(key: string): void;
|
|
24
29
|
invalidateTag(tag: string): void;
|
|
25
30
|
clear(): void;
|
|
31
|
+
/** The current epoch: {@link MemoryCache.setIfFence} compares what changed after it. */
|
|
32
|
+
fence(): number;
|
|
33
|
+
setIfFence(key: string, entry: StoredEntry, tags: readonly string[], token: unknown): boolean;
|
|
26
34
|
/** Live entry count (for observability/tests). */
|
|
27
35
|
size(): number;
|
|
36
|
+
private record;
|
|
28
37
|
/** Remove a key and unlink it from every tag set it belonged to. */
|
|
29
38
|
private evict;
|
|
30
39
|
private sweepExpired;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-cache.d.ts","sourceRoot":"","sources":["../src/memory-cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"memory-cache.d.ts","sourceRoot":"","sources":["../src/memory-cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAazD,MAAM,WAAW,kBAAkB;IACjC;uCACmC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC5B;AAED,qBAAa,WAAY,YAAW,UAAU;IAE5C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAIlC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IACvD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IACvD,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,KAAK,CAAI;gBAEL,OAAO,GAAE,kBAAuB;IAQ5C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAazC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IA0BnE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAOhC,KAAK,IAAI,IAAI;IAUb,wFAAwF;IACxF,KAAK,IAAI,MAAM;IAIf,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO;IAU7F,kDAAkD;IAClD,IAAI,IAAI,MAAM;IAId,OAAO,CAAC,MAAM;IAWd,oEAAoE;IACpE,OAAO,CAAC,KAAK;IAab,OAAO,CAAC,YAAY;CAkBrB"}
|
package/dist/memory-cache.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// How many distinct keys (and, separately, tags) the fence remembers changing. A load that outlives
|
|
2
|
+
// this many distinct changes is refused its write, which costs one cache miss, never a stale value.
|
|
3
|
+
const MAX_TRACKED_CHANGES = 65_536;
|
|
1
4
|
export class MemoryCache {
|
|
2
5
|
// Map iteration is insertion-ordered, so the first key is the LRU victim; `get`/`set` re-insert to touch.
|
|
3
6
|
rows = new Map();
|
|
@@ -5,6 +8,14 @@ export class MemoryCache {
|
|
|
5
8
|
expirySweep = this.rows.entries();
|
|
6
9
|
maxEntries;
|
|
7
10
|
now;
|
|
11
|
+
// The epoch of each key's and tag's latest change, oldest first. Only the change that matters to a
|
|
12
|
+
// load is compared, so unrelated writes never age its fence out. Bounded: a fence older than a
|
|
13
|
+
// forgotten change is refused.
|
|
14
|
+
keyChanges = new Map();
|
|
15
|
+
tagChanges = new Map();
|
|
16
|
+
clearedAt = 0;
|
|
17
|
+
forgottenAt = 0;
|
|
18
|
+
epoch = 0;
|
|
8
19
|
constructor(options = {}) {
|
|
9
20
|
this.maxEntries = options.maxEntries ?? 10_000;
|
|
10
21
|
if (!Number.isSafeInteger(this.maxEntries) || this.maxEntries < 0) {
|
|
@@ -26,6 +37,7 @@ export class MemoryCache {
|
|
|
26
37
|
return { value: row.value, expiresAt: row.expiresAt, staleAt: row.staleAt };
|
|
27
38
|
}
|
|
28
39
|
set(key, entry, tags) {
|
|
40
|
+
this.record(this.keyChanges, key);
|
|
29
41
|
// Incremental expiry keeps cold, high-cardinality keys from occupying the entire bound until
|
|
30
42
|
// their exact key is read. A fixed batch avoids an O(n) latency spike on a write.
|
|
31
43
|
this.sweepExpired(8);
|
|
@@ -51,9 +63,11 @@ export class MemoryCache {
|
|
|
51
63
|
}
|
|
52
64
|
}
|
|
53
65
|
delete(key) {
|
|
66
|
+
this.record(this.keyChanges, key);
|
|
54
67
|
this.evict(key);
|
|
55
68
|
}
|
|
56
69
|
invalidateTag(tag) {
|
|
70
|
+
this.record(this.tagChanges, tag);
|
|
57
71
|
const keys = this.tagIndex.get(tag);
|
|
58
72
|
if (keys === undefined)
|
|
59
73
|
return;
|
|
@@ -61,14 +75,47 @@ export class MemoryCache {
|
|
|
61
75
|
this.evict(key);
|
|
62
76
|
}
|
|
63
77
|
clear() {
|
|
78
|
+
// Every older fence is refused from here on, so the earlier changes need no remembering.
|
|
79
|
+
this.clearedAt = ++this.epoch;
|
|
80
|
+
this.keyChanges.clear();
|
|
81
|
+
this.tagChanges.clear();
|
|
64
82
|
this.rows.clear();
|
|
65
83
|
this.tagIndex.clear();
|
|
66
84
|
this.expirySweep = this.rows.entries();
|
|
67
85
|
}
|
|
86
|
+
/** The current epoch: {@link MemoryCache.setIfFence} compares what changed after it. */
|
|
87
|
+
fence() {
|
|
88
|
+
return this.epoch;
|
|
89
|
+
}
|
|
90
|
+
setIfFence(key, entry, tags, token) {
|
|
91
|
+
if (typeof token !== "number" || !Number.isSafeInteger(token) || token > this.epoch)
|
|
92
|
+
return false;
|
|
93
|
+
if (token < this.clearedAt || token < this.forgottenAt)
|
|
94
|
+
return false;
|
|
95
|
+
if ((this.keyChanges.get(key) ?? 0) > token)
|
|
96
|
+
return false;
|
|
97
|
+
for (const tag of tags)
|
|
98
|
+
if ((this.tagChanges.get(tag) ?? 0) > token)
|
|
99
|
+
return false;
|
|
100
|
+
this.set(key, entry, tags);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
68
103
|
/** Live entry count (for observability/tests). */
|
|
69
104
|
size() {
|
|
70
105
|
return this.rows.size;
|
|
71
106
|
}
|
|
107
|
+
record(changes, name) {
|
|
108
|
+
changes.delete(name);
|
|
109
|
+
changes.set(name, ++this.epoch);
|
|
110
|
+
if (changes.size <= MAX_TRACKED_CHANGES)
|
|
111
|
+
return;
|
|
112
|
+
const first = changes.entries().next();
|
|
113
|
+
if (first.done)
|
|
114
|
+
return;
|
|
115
|
+
const [oldest, at] = first.value;
|
|
116
|
+
changes.delete(oldest);
|
|
117
|
+
this.forgottenAt = Math.max(this.forgottenAt, at);
|
|
118
|
+
}
|
|
72
119
|
/** Remove a key and unlink it from every tag set it belonged to. */
|
|
73
120
|
evict(key) {
|
|
74
121
|
const row = this.rows.get(key);
|
package/dist/memory-cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-cache.js","sourceRoot":"","sources":["../src/memory-cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"memory-cache.js","sourceRoot":"","sources":["../src/memory-cache.ts"],"names":[],"mappings":"AAcA,oGAAoG;AACpG,oGAAoG;AACpG,MAAM,mBAAmB,GAAG,MAAM,CAAA;AAUlC,MAAM,OAAO,WAAW;IACtB,0GAA0G;IACzF,IAAI,GAAG,IAAI,GAAG,EAAe,CAAA;IAC7B,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAA;IAClD,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA;IACxB,UAAU,CAAQ;IAClB,GAAG,CAAc;IAClC,mGAAmG;IACnG,+FAA+F;IAC/F,+BAA+B;IACd,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;IACtC,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC/C,SAAS,GAAG,CAAC,CAAA;IACb,WAAW,GAAG,CAAC,CAAA;IACf,KAAK,GAAG,CAAC,CAAA;IAEjB,YAAY,UAA8B,EAAE;QAC1C,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,MAAM,CAAA;QAC9C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,UAAU,CAAC,6DAA6D,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC9B,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,SAAS,CAAA;QACvC,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YACf,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,aAAa;QACb,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QACvB,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAA;IAC7E,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAkB,EAAE,IAAuB;QAC1D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;QACjC,6FAA6F;QAC7F,kFAAkF;QAClF,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACpB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA,CAAC,+CAA+C;QAC/D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;YACjB,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI;SACL,CAAC,CAAA;QACF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,GAAG,GAAG,IAAI,GAAG,EAAE,CAAA;gBACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YAC7B,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACd,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;QACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACjB,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAM;QAC9B,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC9C,CAAC;IAED,KAAK;QACH,yFAAyF;QACzF,IAAI,CAAC,SAAS,GAAG,EAAE,IAAI,CAAC,KAAK,CAAA;QAC7B,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;QACvB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;QACvB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;QACjB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;QACrB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA;IACxC,CAAC;IAED,wFAAwF;IACxF,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,UAAU,CAAC,GAAW,EAAE,KAAkB,EAAE,IAAuB,EAAE,KAAc;QACjF,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK;YACjF,OAAO,KAAK,CAAA;QACd,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAA;QACpE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK;YAAE,OAAO,KAAK,CAAA;QACzD,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK;gBAAE,OAAO,KAAK,CAAA;QACjF,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QAC1B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,kDAAkD;IAClD,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;IACvB,CAAC;IAEO,MAAM,CAAC,OAA4B,EAAE,IAAY;QACvD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACpB,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAC/B,IAAI,OAAO,CAAC,IAAI,IAAI,mBAAmB;YAAE,OAAM;QAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAA;QACtC,IAAI,KAAK,CAAC,IAAI;YAAE,OAAM;QACtB,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAA;QAChC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACtB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IACnD,CAAC;IAED,oEAAoE;IAC5D,KAAK,CAAC,GAAW;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC9B,IAAI,GAAG,KAAK,SAAS;YAAE,OAAM;QAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACrB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAClC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBACf,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;oBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK,GAAI,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAA;YACpC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,IAAI,SAAS;oBAAE,OAAM,CAAC,+DAA+D;gBACrF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA;gBACtC,SAAS,GAAG,IAAI,CAAA;gBAChB,SAAQ;YACV,CAAC;YACD,SAAS,GAAG,KAAK,CAAA;YACjB,OAAO,EAAE,CAAA;YACT,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAA;YAC7B,+FAA+F;YAC/F,wEAAwE;YACxE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,SAAS;gBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAChF,CAAC;IACH,CAAC;CACF"}
|
package/dist/types.d.ts
CHANGED
|
@@ -26,7 +26,22 @@ export interface CacheStore {
|
|
|
26
26
|
/** Drop every entry carrying `tag`. */
|
|
27
27
|
invalidateTag(tag: string): void | Promise<void>;
|
|
28
28
|
clear(): void | Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Optional, with {@link CacheStore.setIfFence}, for a store several caches or processes share. An
|
|
31
|
+
* opaque token naming this moment for `key` and `tags`. A `wrap` load takes one before it starts.
|
|
32
|
+
*/
|
|
33
|
+
fence?(key: string, tags: readonly string[]): unknown | Promise<unknown>;
|
|
34
|
+
/**
|
|
35
|
+
* Optional, with {@link CacheStore.fence}. Store `entry` only when nothing has run since `fence`
|
|
36
|
+
* returned `token` that a load must not overwrite: a `set` or `delete` of `key`, an `invalidateTag`
|
|
37
|
+
* of one of `tags`, or a `clear`, from any cache sharing the store. The check and the write are one
|
|
38
|
+
* atomic step. Resolves `true` when it wrote. A store that cannot tell may refuse; the load's value
|
|
39
|
+
* still reaches its caller, it is just not cached.
|
|
40
|
+
*/
|
|
41
|
+
setIfFence?(key: string, entry: StoredEntry, tags: readonly string[], token: unknown): boolean | Promise<boolean>;
|
|
29
42
|
}
|
|
43
|
+
/** The store call a {@link CacheOptions.onStoreError} report is about. */
|
|
44
|
+
export type CacheStoreOp = "get" | "set" | "fence";
|
|
30
45
|
export interface SetOptions {
|
|
31
46
|
/** Time-to-live (ms) before the value goes stale. Default: the cache's `defaultTtlMs`. */
|
|
32
47
|
readonly ttlMs?: number;
|
|
@@ -104,6 +119,14 @@ export interface CacheOptions {
|
|
|
104
119
|
readonly now?: () => number;
|
|
105
120
|
/** Called when a background SWR revalidation throws. Default: `console.error`. */
|
|
106
121
|
readonly onError?: (error: unknown, key: string) => void;
|
|
122
|
+
/**
|
|
123
|
+
* Called when `wrap` meets a store failure: a `get` that throws or rejects is answered as a miss, so
|
|
124
|
+
* the loader runs, and a `set` that fails still returns the loaded value. A `fence` that fails
|
|
125
|
+
* leaves that load uncached. Other operations reject as before. Default: one `console.error` line per operation per minute, never naming the key.
|
|
126
|
+
*/
|
|
127
|
+
readonly onStoreError?: (error: unknown, info: {
|
|
128
|
+
readonly op: CacheStoreOp;
|
|
129
|
+
}) => void;
|
|
107
130
|
/**
|
|
108
131
|
* Receives one {@link CacheEvent} per operation - the seam `cacheTracing()` from `@nifrajs/otel/cache`
|
|
109
132
|
* plugs into. Without one the cache reads no extra clock and allocates no event.
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nifrajs/cache",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Typed KV cache for nifra - TTL, stale-while-revalidate, tag invalidation, and single-flight stampede protection on a pluggable store (in-memory default; bring CF KV / Redis). Dependency-free, runs on Bun/Node/Deno/Workers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
package/src/cache.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
CacheOptions,
|
|
20
20
|
CacheOutcome,
|
|
21
21
|
CacheStore,
|
|
22
|
+
CacheStoreOp,
|
|
22
23
|
SetOptions,
|
|
23
24
|
StoredEntry,
|
|
24
25
|
WrapOptions,
|
|
@@ -30,6 +31,18 @@ function assertDuration(value: number, name: string): void {
|
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
const STORE_REPORT_INTERVAL_MS = 60_000
|
|
35
|
+
const STORE_REPORT_DETAIL_CHARS = 200
|
|
36
|
+
|
|
37
|
+
/** The error's own words with the key cut out, since a store may name the key it failed on. */
|
|
38
|
+
function storeErrorDetail(error: unknown, key: string): string {
|
|
39
|
+
const text = error instanceof Error ? `${error.name}: ${error.message}` : String(error)
|
|
40
|
+
const redacted = key === "" ? text : text.split(key).join("<key>")
|
|
41
|
+
return redacted.length > STORE_REPORT_DETAIL_CHARS
|
|
42
|
+
? `${redacted.slice(0, STORE_REPORT_DETAIL_CHARS)}...`
|
|
43
|
+
: redacted
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
function notify(observer: CacheObserver, event: CacheEvent): void {
|
|
34
47
|
try {
|
|
35
48
|
const result: unknown = observer(event)
|
|
@@ -73,9 +86,68 @@ export function createCache(options: CacheOptions = {}): Cache {
|
|
|
73
86
|
((error, key) =>
|
|
74
87
|
console.error(`[nifra/cache] revalidate ${JSON.stringify(key)} failed:`, error))
|
|
75
88
|
|
|
89
|
+
const lastStoreReport = new Map<CacheStoreOp, number>()
|
|
90
|
+
const reportStoreError = (op: CacheStoreOp, key: string, error: unknown): void => {
|
|
91
|
+
try {
|
|
92
|
+
if (options.onStoreError !== undefined) {
|
|
93
|
+
options.onStoreError(error, { op })
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
const last = lastStoreReport.get(op)
|
|
97
|
+
const at = now()
|
|
98
|
+
if (last !== undefined && at - last < STORE_REPORT_INTERVAL_MS) return
|
|
99
|
+
lastStoreReport.set(op, at)
|
|
100
|
+
console.error(
|
|
101
|
+
`[nifra/cache] store ${op} failed; loading without the cache (${storeErrorDetail(error, key)})`,
|
|
102
|
+
)
|
|
103
|
+
} catch {
|
|
104
|
+
// A failing reporter must not turn a loaded value into an error.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** `wrap`'s read: a store that throws or rejects is a miss, so the loader answers. */
|
|
108
|
+
const readEntry = async (key: string): Promise<StoredEntry | undefined> => {
|
|
109
|
+
try {
|
|
110
|
+
return await store.get(key)
|
|
111
|
+
} catch (error) {
|
|
112
|
+
reportStoreError("get", key, error)
|
|
113
|
+
return undefined
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
76
117
|
const observer = options.observer
|
|
77
118
|
// Single-flight: concurrent loads for the same key share one promise (miss stampede + SWR dedup).
|
|
78
|
-
|
|
119
|
+
// A delete, tag invalidation, clear or newer set withdraws a load's right to store its result, so
|
|
120
|
+
// a refresh that started before the invalidation cannot write the old value back. A store with
|
|
121
|
+
// `fence`/`setIfFence` also refuses a load's write after such a change from another cache sharing
|
|
122
|
+
// it, and a delete, invalidation or clear waits for this cache's async writes it covers, so a store
|
|
123
|
+
// that applies requests out of order cannot land one of them after it.
|
|
124
|
+
const inflight = new Map<
|
|
125
|
+
string,
|
|
126
|
+
{ readonly promise: Promise<unknown>; readonly tags: readonly string[]; withdraw(): void }
|
|
127
|
+
>()
|
|
128
|
+
const withdraw = (matches: (key: string, tags: readonly string[]) => boolean): void => {
|
|
129
|
+
for (const [key, flight] of inflight) {
|
|
130
|
+
if (!matches(key, flight.tags)) continue
|
|
131
|
+
flight.withdraw()
|
|
132
|
+
inflight.delete(key)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const fencing = typeof store.fence === "function" && typeof store.setIfFence === "function"
|
|
136
|
+
const writing = new Set<{
|
|
137
|
+
readonly key: string
|
|
138
|
+
readonly tags: readonly string[]
|
|
139
|
+
readonly done: Promise<unknown>
|
|
140
|
+
}>()
|
|
141
|
+
// Run a delete, invalidation or clear after every async write it covers has settled.
|
|
142
|
+
const after = (
|
|
143
|
+
matches: (key: string, tags: readonly string[]) => boolean,
|
|
144
|
+
change: () => void | Promise<void>,
|
|
145
|
+
): Promise<void> => {
|
|
146
|
+
const covered: Promise<unknown>[] = []
|
|
147
|
+
for (const write of writing) if (matches(write.key, write.tags)) covered.push(write.done)
|
|
148
|
+
if (covered.length === 0) return Promise.resolve(change())
|
|
149
|
+
return Promise.allSettled(covered).then(change)
|
|
150
|
+
}
|
|
79
151
|
|
|
80
152
|
async function get<T = unknown>(key: string): Promise<T | undefined> {
|
|
81
153
|
const entry = await store.get(key)
|
|
@@ -86,30 +158,104 @@ export function createCache(options: CacheOptions = {}): Cache {
|
|
|
86
158
|
return (await store.get(key)) !== undefined
|
|
87
159
|
}
|
|
88
160
|
|
|
89
|
-
|
|
161
|
+
function entryOf(value: unknown, opts: SetOptions): StoredEntry {
|
|
90
162
|
const ttlMs = opts.ttlMs ?? defaultTtlMs
|
|
91
163
|
const swrMs = opts.swrMs ?? 0
|
|
92
164
|
assertDuration(ttlMs, "ttlMs")
|
|
93
165
|
assertDuration(swrMs, "swrMs")
|
|
94
166
|
const t = now()
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
167
|
+
return { value, staleAt: t + ttlMs, expiresAt: t + ttlMs + swrMs }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function put(
|
|
171
|
+
key: string,
|
|
172
|
+
entry: StoredEntry,
|
|
173
|
+
tags: readonly string[],
|
|
174
|
+
fenced?: { readonly token: unknown },
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
const pending =
|
|
177
|
+
fenced !== undefined && store.setIfFence !== undefined
|
|
178
|
+
? store.setIfFence(key, entry, tags, fenced.token)
|
|
179
|
+
: store.set(key, entry, tags)
|
|
180
|
+
if (!(pending instanceof Promise)) return
|
|
181
|
+
const record = { key, tags, done: pending }
|
|
182
|
+
writing.add(record)
|
|
183
|
+
try {
|
|
184
|
+
await pending
|
|
185
|
+
} finally {
|
|
186
|
+
writing.delete(record)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function write<T>(key: string, value: T, opts: SetOptions): Promise<void> {
|
|
191
|
+
await put(key, entryOf(value, opts), opts.tags ?? [])
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function set<T>(key: string, value: T, opts: SetOptions = {}): Promise<void> {
|
|
195
|
+
withdraw((flightKey) => flightKey === key)
|
|
196
|
+
return write(key, value, opts)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function remove(key: string): Promise<void> {
|
|
200
|
+
const matches = (writeKey: string): boolean => writeKey === key
|
|
201
|
+
withdraw(matches)
|
|
202
|
+
return after(matches, () => store.delete(key))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function invalidateTag(tag: string): Promise<void> {
|
|
206
|
+
const matches = (_key: string, tags: readonly string[]): boolean => tags.includes(tag)
|
|
207
|
+
withdraw(matches)
|
|
208
|
+
return after(matches, () => store.invalidateTag(tag))
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function clear(): Promise<void> {
|
|
212
|
+
withdraw(() => true)
|
|
213
|
+
return after(
|
|
214
|
+
() => true,
|
|
215
|
+
() => store.clear(),
|
|
99
216
|
)
|
|
100
217
|
}
|
|
101
218
|
|
|
102
219
|
function load(key: string, loader: () => unknown, opts: WrapOptions): Promise<unknown> {
|
|
103
220
|
const existing = inflight.get(key)
|
|
104
|
-
if (existing !== undefined) return existing
|
|
221
|
+
if (existing !== undefined) return existing.promise
|
|
222
|
+
let withdrawn = false
|
|
105
223
|
const p = (async () => {
|
|
224
|
+
// Taken before the loader runs, so a change from another cache during the load refuses its
|
|
225
|
+
// write. Awaited only when async: a sync store keeps the loader starting synchronously.
|
|
226
|
+
let fenced: { readonly token: unknown } | undefined
|
|
227
|
+
let storable = true
|
|
228
|
+
if (fencing) {
|
|
229
|
+
try {
|
|
230
|
+
const token = store.fence?.(key, opts.tags ?? [])
|
|
231
|
+
fenced = { token: token instanceof Promise ? await token : token }
|
|
232
|
+
} catch (error) {
|
|
233
|
+
// Without a token the write could land after another cache's invalidation: load uncached.
|
|
234
|
+
reportStoreError("fence", key, error)
|
|
235
|
+
storable = false
|
|
236
|
+
}
|
|
237
|
+
}
|
|
106
238
|
const value = await loader()
|
|
107
|
-
|
|
239
|
+
if (!withdrawn && storable) {
|
|
240
|
+
// Built outside the try: a bad ttlMs is the caller's error, not a store outage.
|
|
241
|
+
const entry = entryOf(value, opts)
|
|
242
|
+
try {
|
|
243
|
+
await put(key, entry, opts.tags ?? [], fenced)
|
|
244
|
+
} catch (error) {
|
|
245
|
+
reportStoreError("set", key, error)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
108
248
|
return value
|
|
109
249
|
})().finally(() => {
|
|
110
|
-
if (inflight.get(key) === p) inflight.delete(key)
|
|
250
|
+
if (inflight.get(key)?.promise === p) inflight.delete(key)
|
|
251
|
+
})
|
|
252
|
+
inflight.set(key, {
|
|
253
|
+
promise: p,
|
|
254
|
+
tags: opts.tags ?? [],
|
|
255
|
+
withdraw: () => {
|
|
256
|
+
withdrawn = true
|
|
257
|
+
},
|
|
111
258
|
})
|
|
112
|
-
inflight.set(key, p)
|
|
113
259
|
return p
|
|
114
260
|
}
|
|
115
261
|
|
|
@@ -143,7 +289,7 @@ export function createCache(options: CacheOptions = {}): Cache {
|
|
|
143
289
|
loader: () => T,
|
|
144
290
|
opts: WrapOptions = {},
|
|
145
291
|
): Promise<Awaited<T>> {
|
|
146
|
-
const entry = await
|
|
292
|
+
const entry = await readEntry(key)
|
|
147
293
|
if (entry !== undefined) {
|
|
148
294
|
if (now() < entry.staleAt) return entry.value as Awaited<T> // fresh hit
|
|
149
295
|
revalidate(key, loader as () => unknown, opts, undefined) // stale-but-live → serve stale, refresh in background
|
|
@@ -200,7 +346,7 @@ export function createCache(options: CacheOptions = {}): Cache {
|
|
|
200
346
|
const started = performance.now()
|
|
201
347
|
let outcome: CacheOutcome = "error"
|
|
202
348
|
try {
|
|
203
|
-
const entry = await
|
|
349
|
+
const entry = await readEntry(key)
|
|
204
350
|
if (entry !== undefined) {
|
|
205
351
|
outcome = readOutcome(entry)
|
|
206
352
|
if (outcome === "stale") revalidate(key, loader, opts, context)
|
|
@@ -224,19 +370,10 @@ export function createCache(options: CacheOptions = {}): Cache {
|
|
|
224
370
|
)
|
|
225
371
|
}
|
|
226
372
|
},
|
|
227
|
-
delete: (key) =>
|
|
228
|
-
settle("delete", key, undefined, 0, () => Promise.resolve(store.delete(key)), "ok"),
|
|
373
|
+
delete: (key) => settle("delete", key, undefined, 0, () => remove(key), "ok"),
|
|
229
374
|
invalidateTag: (tag) =>
|
|
230
|
-
settle(
|
|
231
|
-
|
|
232
|
-
undefined,
|
|
233
|
-
tag,
|
|
234
|
-
1,
|
|
235
|
-
() => Promise.resolve(store.invalidateTag(tag)),
|
|
236
|
-
"ok",
|
|
237
|
-
),
|
|
238
|
-
clear: () =>
|
|
239
|
-
settle("clear", undefined, undefined, 0, () => Promise.resolve(store.clear()), "ok"),
|
|
375
|
+
settle("invalidateTag", undefined, tag, 1, () => invalidateTag(tag), "ok"),
|
|
376
|
+
clear: () => settle("clear", undefined, undefined, 0, clear, "ok"),
|
|
240
377
|
for: bind,
|
|
241
378
|
}
|
|
242
379
|
}
|
|
@@ -251,9 +388,9 @@ export function createCache(options: CacheOptions = {}): Cache {
|
|
|
251
388
|
has,
|
|
252
389
|
set,
|
|
253
390
|
wrap,
|
|
254
|
-
delete:
|
|
255
|
-
invalidateTag
|
|
256
|
-
clear
|
|
391
|
+
delete: remove,
|
|
392
|
+
invalidateTag,
|
|
393
|
+
clear,
|
|
257
394
|
for: bind,
|
|
258
395
|
}
|
|
259
396
|
: observed(observer, undefined)
|
package/src/index.ts
CHANGED
package/src/memory-cache.ts
CHANGED
|
@@ -12,6 +12,10 @@ interface Row {
|
|
|
12
12
|
tags: readonly string[]
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// How many distinct keys (and, separately, tags) the fence remembers changing. A load that outlives
|
|
16
|
+
// this many distinct changes is refused its write, which costs one cache miss, never a stale value.
|
|
17
|
+
const MAX_TRACKED_CHANGES = 65_536
|
|
18
|
+
|
|
15
19
|
export interface MemoryCacheOptions {
|
|
16
20
|
/** Evict the least-recently-used entry once the count exceeds this. Default 10,000; `0` explicitly
|
|
17
21
|
* opts into an unbounded cache. */
|
|
@@ -27,6 +31,14 @@ export class MemoryCache implements CacheStore {
|
|
|
27
31
|
private expirySweep = this.rows.entries()
|
|
28
32
|
private readonly maxEntries: number
|
|
29
33
|
private readonly now: () => number
|
|
34
|
+
// The epoch of each key's and tag's latest change, oldest first. Only the change that matters to a
|
|
35
|
+
// load is compared, so unrelated writes never age its fence out. Bounded: a fence older than a
|
|
36
|
+
// forgotten change is refused.
|
|
37
|
+
private readonly keyChanges = new Map<string, number>()
|
|
38
|
+
private readonly tagChanges = new Map<string, number>()
|
|
39
|
+
private clearedAt = 0
|
|
40
|
+
private forgottenAt = 0
|
|
41
|
+
private epoch = 0
|
|
30
42
|
|
|
31
43
|
constructor(options: MemoryCacheOptions = {}) {
|
|
32
44
|
this.maxEntries = options.maxEntries ?? 10_000
|
|
@@ -50,6 +62,7 @@ export class MemoryCache implements CacheStore {
|
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
set(key: string, entry: StoredEntry, tags: readonly string[]): void {
|
|
65
|
+
this.record(this.keyChanges, key)
|
|
53
66
|
// Incremental expiry keeps cold, high-cardinality keys from occupying the entire bound until
|
|
54
67
|
// their exact key is read. A fixed batch avoids an O(n) latency spike on a write.
|
|
55
68
|
this.sweepExpired(8)
|
|
@@ -75,26 +88,58 @@ export class MemoryCache implements CacheStore {
|
|
|
75
88
|
}
|
|
76
89
|
|
|
77
90
|
delete(key: string): void {
|
|
91
|
+
this.record(this.keyChanges, key)
|
|
78
92
|
this.evict(key)
|
|
79
93
|
}
|
|
80
94
|
|
|
81
95
|
invalidateTag(tag: string): void {
|
|
96
|
+
this.record(this.tagChanges, tag)
|
|
82
97
|
const keys = this.tagIndex.get(tag)
|
|
83
98
|
if (keys === undefined) return
|
|
84
99
|
for (const key of [...keys]) this.evict(key)
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
clear(): void {
|
|
103
|
+
// Every older fence is refused from here on, so the earlier changes need no remembering.
|
|
104
|
+
this.clearedAt = ++this.epoch
|
|
105
|
+
this.keyChanges.clear()
|
|
106
|
+
this.tagChanges.clear()
|
|
88
107
|
this.rows.clear()
|
|
89
108
|
this.tagIndex.clear()
|
|
90
109
|
this.expirySweep = this.rows.entries()
|
|
91
110
|
}
|
|
92
111
|
|
|
112
|
+
/** The current epoch: {@link MemoryCache.setIfFence} compares what changed after it. */
|
|
113
|
+
fence(): number {
|
|
114
|
+
return this.epoch
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
setIfFence(key: string, entry: StoredEntry, tags: readonly string[], token: unknown): boolean {
|
|
118
|
+
if (typeof token !== "number" || !Number.isSafeInteger(token) || token > this.epoch)
|
|
119
|
+
return false
|
|
120
|
+
if (token < this.clearedAt || token < this.forgottenAt) return false
|
|
121
|
+
if ((this.keyChanges.get(key) ?? 0) > token) return false
|
|
122
|
+
for (const tag of tags) if ((this.tagChanges.get(tag) ?? 0) > token) return false
|
|
123
|
+
this.set(key, entry, tags)
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
|
|
93
127
|
/** Live entry count (for observability/tests). */
|
|
94
128
|
size(): number {
|
|
95
129
|
return this.rows.size
|
|
96
130
|
}
|
|
97
131
|
|
|
132
|
+
private record(changes: Map<string, number>, name: string): void {
|
|
133
|
+
changes.delete(name)
|
|
134
|
+
changes.set(name, ++this.epoch)
|
|
135
|
+
if (changes.size <= MAX_TRACKED_CHANGES) return
|
|
136
|
+
const first = changes.entries().next()
|
|
137
|
+
if (first.done) return
|
|
138
|
+
const [oldest, at] = first.value
|
|
139
|
+
changes.delete(oldest)
|
|
140
|
+
this.forgottenAt = Math.max(this.forgottenAt, at)
|
|
141
|
+
}
|
|
142
|
+
|
|
98
143
|
/** Remove a key and unlink it from every tag set it belonged to. */
|
|
99
144
|
private evict(key: string): void {
|
|
100
145
|
const row = this.rows.get(key)
|
package/src/types.ts
CHANGED
|
@@ -28,8 +28,29 @@ export interface CacheStore {
|
|
|
28
28
|
/** Drop every entry carrying `tag`. */
|
|
29
29
|
invalidateTag(tag: string): void | Promise<void>
|
|
30
30
|
clear(): void | Promise<void>
|
|
31
|
+
/**
|
|
32
|
+
* Optional, with {@link CacheStore.setIfFence}, for a store several caches or processes share. An
|
|
33
|
+
* opaque token naming this moment for `key` and `tags`. A `wrap` load takes one before it starts.
|
|
34
|
+
*/
|
|
35
|
+
fence?(key: string, tags: readonly string[]): unknown | Promise<unknown>
|
|
36
|
+
/**
|
|
37
|
+
* Optional, with {@link CacheStore.fence}. Store `entry` only when nothing has run since `fence`
|
|
38
|
+
* returned `token` that a load must not overwrite: a `set` or `delete` of `key`, an `invalidateTag`
|
|
39
|
+
* of one of `tags`, or a `clear`, from any cache sharing the store. The check and the write are one
|
|
40
|
+
* atomic step. Resolves `true` when it wrote. A store that cannot tell may refuse; the load's value
|
|
41
|
+
* still reaches its caller, it is just not cached.
|
|
42
|
+
*/
|
|
43
|
+
setIfFence?(
|
|
44
|
+
key: string,
|
|
45
|
+
entry: StoredEntry,
|
|
46
|
+
tags: readonly string[],
|
|
47
|
+
token: unknown,
|
|
48
|
+
): boolean | Promise<boolean>
|
|
31
49
|
}
|
|
32
50
|
|
|
51
|
+
/** The store call a {@link CacheOptions.onStoreError} report is about. */
|
|
52
|
+
export type CacheStoreOp = "get" | "set" | "fence"
|
|
53
|
+
|
|
33
54
|
export interface SetOptions {
|
|
34
55
|
/** Time-to-live (ms) before the value goes stale. Default: the cache's `defaultTtlMs`. */
|
|
35
56
|
readonly ttlMs?: number
|
|
@@ -123,6 +144,12 @@ export interface CacheOptions {
|
|
|
123
144
|
readonly now?: () => number
|
|
124
145
|
/** Called when a background SWR revalidation throws. Default: `console.error`. */
|
|
125
146
|
readonly onError?: (error: unknown, key: string) => void
|
|
147
|
+
/**
|
|
148
|
+
* Called when `wrap` meets a store failure: a `get` that throws or rejects is answered as a miss, so
|
|
149
|
+
* the loader runs, and a `set` that fails still returns the loaded value. A `fence` that fails
|
|
150
|
+
* leaves that load uncached. Other operations reject as before. Default: one `console.error` line per operation per minute, never naming the key.
|
|
151
|
+
*/
|
|
152
|
+
readonly onStoreError?: (error: unknown, info: { readonly op: CacheStoreOp }) => void
|
|
126
153
|
/**
|
|
127
154
|
* Receives one {@link CacheEvent} per operation - the seam `cacheTracing()` from `@nifrajs/otel/cache`
|
|
128
155
|
* plugs into. Without one the cache reads no extra clock and allocates no event.
|