-
-
Notifications
You must be signed in to change notification settings - Fork 29
Description
I've encountered an issue where calling deleteByTag does not properly invalidate cached values when a grace period is configured. After invalidation, the cache still returns the stale ("old") value for getOrSet.
Initially, I suspected this behavior was limited to distributed setups using a bus, but it also occurs with a single cache instance. This suggests the issue is not related to multi-node synchronization but possibly to how deleteByTag interacts with the grace logic.
For reproduction, I quickly wrote two test cases in tagging.spec.ts on my local machine:
test('remove by tags with grace period', async ({ assert }) => {
const [cache] = new CacheFactory().withL1L2Config().create()
const v1 = await cache.getOrSet({
key: 'baz',
factory: () => 1,
tags: ['x', 'z'],
ttl: '2min',
grace: '10min',
})
assert.deepEqual(v1, 1)
await cache.deleteByTag({ tags: ['x'] })
const v2get = await cache.get({ key: 'baz' })
const v2getorset = await cache.getOrSet({
key: 'baz',
factory: () => 2,
tags: ['x', 'z'],
ttl: '2min',
grace: '10min',
})
assert.isUndefined(v2get)
assert.deepEqual(v2getorset, 2)
})
test('remove by tags with bus and grace period', async ({ assert }) => {
const [readCache] = new CacheFactory().withL1L2Config().create()
const [invalidationCache] = new CacheFactory().withL1L2Config().create()
const v1 = await readCache.getOrSet({
key: 'baz',
factory: () => 1,
tags: ['x', 'z'],
ttl: '2min',
grace: '10min',
})
assert.deepEqual(v1, 1)
await invalidationCache.deleteByTag({ tags: ['x'] })
//await invalidationCache.delete({ key: 'baz' }) <- this works btw.
const v2get = await readCache.get({ key: 'baz' })
const v2getorset = await readCache.getOrSet({
key: 'baz',
factory: () => 2,
tags: ['x', 'z'],
ttl: '2min',
grace: '10min',
})
assert.isUndefined(v2get)
assert.deepEqual(v2getorset, 2)
})Result:
> cross-env NODE_NO_WARNINGS=1 node --enable-source-maps --loader=ts-node/esm bin/test.ts "--suite=unit" "--files=tests/tagging.spec.ts"
unit / Tagging | Internals (tests/tagging.spec.ts)
β deleteByTag should store invalidated tags with timestamps (7.08ms)
β set should store value with tags (2.1ms)
unit / Tagging | deleteByTag (tests/tagging.spec.ts)
β basic (2.94ms)
β can remove by tag (6.51ms)
β can remove multiple tags (3.6ms)
β remove by tags with bus (6.01ms)
β remove by tags with grace period (2.74ms)
β remove by tags with bus and grace period (2.99ms)
β remove multiple tags with bus (8.59ms)
β tags and namespaces (3.56ms)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ERRORS βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β― Tagging | deleteByTag / remove by tags with grace period
- Expected - 1
+ Received + 1
- 2
+ 1
βΉ AssertionError: expected 1 to deeply equal 2
β at Assert.deepEqual (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@japa/assert/build/index.js:282:19)
β at Object.executor (tests/tagging.spec.ts:192:12)
187 β ttl: '2min',
188 β grace: '10min',
189 β })
190 β
191 β assert.isUndefined(v2get)
β― 192 β assert.deepEqual(v2getorset, 2)
193 β })
194 β
195 β test('remove by tags with bus and grace period', async ({ assert }) => {
196 β const [readCache] = new CacheFactory().withL1L2Config().create()
197 β const [invalidationCache] = new CacheFactory().withL1L2Config().create()
β at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
β at async #wrapTestInTimeout (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:1054:7)
β at async TestRunner.run (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:1102:7)
β at async Test.exec (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:1482:5)
β at async GroupRunner.run (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:345:7)
β at async Group.exec (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:513:5)
β at async SuiteRunner.run (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:1809:7)
β at async Suite.exec (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]/node_modules/@japa/core/build/index.js:1936:5)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ[1/2]β
β― Tagging | deleteByTag / remove by tags with bus and grace period
- Expected - 1
+ Received + 1
- 2
+ 1
βΉ AssertionError: expected 1 to deeply equal 2
β at Assert.deepEqual (/Users/yss/Dev/open-source/bentocache/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@japa/assert/build/index.js:282:19)
β at Object.executor (tests/tagging.spec.ts:222:12)
217 β ttl: '2min',
218 β grace: '10min',
219 β })
220 β
221 β assert.isUndefined(v2get)
β― 222 β assert.deepEqual(v2getorset, 2)
223 β })
At this point, I'm not sure whether this is intended behavior or a bug. However, I would lean toward it being a bugβespecially since the interaction between deleteByTag and the grace period doesnβt appear to be covered by the existing test suite.