From 023b116ad3d79ed6efe57e106beadc26d9d385f6 Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Mon, 19 Oct 2026 17:41:58 -0400 Subject: [PATCH] Prune each stored refresh by its own keep time --- api/src/latest.js | 11 ++++++----- api/test/latest.test.js | 11 +++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/api/src/latest.js b/api/src/latest.js index 6de6ce2c..5302cf04 100644 --- a/api/src/latest.js +++ b/api/src/latest.js @@ -4,11 +4,11 @@ /** @typedef {{ ok: true, value: any } | { ok: false, error: unknown }} Outcome */ -/** @type {Map | null, group: string | null }>} */ +/** @type {Map | null, group: string | null }>} */ const _entries = new Map(); -function prune(now, keepMs) { - for (const [key, e] of _entries) if (!e.pending && now - e.at >= keepMs) _entries.delete(key); +function prune(now) { + for (const [key, e] of _entries) if (!e.pending && now - e.at >= e.keepMs) _entries.delete(key); } /* Drops the oldest settled entries of a group until at most max remain. A @@ -40,13 +40,14 @@ function within(ms, pending) { @returns {Promise} */ async function latest(key, refresh, { holdMs, keepMs, group, maxPerGroup }) { const now = Date.now(); - prune(now, keepMs); + prune(now); let e = _entries.get(key); const created = !e; if (!e) { - e = { started: 0, at: 0, outcome: null, pending: null, group: group ?? null }; + e = { started: 0, at: 0, keepMs, outcome: null, pending: null, group: group ?? null }; _entries.set(key, e); } + e.keepMs = keepMs; const entry = e; if (!entry.pending) { entry.started = now; diff --git a/api/test/latest.test.js b/api/test/latest.test.js index 9cb5798d..6047cccd 100644 --- a/api/test/latest.test.js +++ b/api/test/latest.test.js @@ -61,6 +61,17 @@ test('a result older than keepMs is not used', async t => { assert.equal(await latest('k', () => new Promise(() => {}), { holdMs: 0, keepMs: OPTS.keepMs }), null); }); +test('a short keepMs on one key does not drop another key kept longer', async t => { + t.mock.timers.enable({ apis: ['Date'], now: 1_000_000 }); + await latest('long', async () => 'kept', { holdMs: 30, keepMs: 15 * 60_000 }); + t.mock.timers.tick(5 * 60_000); + await latest('short', async () => 'other', { holdMs: 30, keepMs: 2 * 60_000 }); + assert.deepEqual(await latest('long', () => new Promise(() => {}), { holdMs: 0, keepMs: 15 * 60_000 }), { + ok: true, + value: 'kept', + }); +}); + test('different keys do not share a result', async () => { await latest('a', async () => 'a', OPTS); assert.deepEqual(await latest('b', async () => 'b', OPTS), { ok: true, value: 'b' });