Skip to content

feat(@cacheable/node-cache): enhance NodeCacheStore with missing features#1643

Merged
jaredwray merged 5 commits into
mainfrom
claude/friendly-bohr-veUyM
May 26, 2026
Merged

feat(@cacheable/node-cache): enhance NodeCacheStore with missing features#1643
jaredwray merged 5 commits into
mainfrom
claude/friendly-bohr-veUyM

Conversation

@jaredwray
Copy link
Copy Markdown
Owner

Summary

  • keys() and has() — fundamental inspection methods with expiration-aware checks
  • getTtl() — inspect a key's expiration timestamp (returns 0 for unlimited, undefined for missing, or ms timestamp)
  • flushAll() — clears all data, resets all stats, and emits a "flush" event (unlike clear() which only resets store values)
  • Events — emits "set", "del", "expired", "flush" events on corresponding operations, matching NodeCache's event model
  • useClones — option to deep-clone values via structuredClone on get/set, preventing mutation of cached data
  • checkperiod — interval-based expired item detection with configurable period in seconds
  • deleteOnExpire — option to control automatic deletion of expired items
  • close() / getIntervalId() — interval lifecycle management

Bug fixes found during code review

  • setTtl() falsy-zero: if (item) treated cached values of 0, "", false, null as non-existent; fixed to if (item !== undefined)
  • mdel() unconditional stats: stats and events fired for non-existent keys and before actual Keyv delete; now delegates to del() for proper guarding
  • startInterval() timer leak: calling twice leaked the old interval; now calls stopInterval() first
  • set() overwrite double-counting: overwriting a key doubled stats (count, ksize, vsize); now adjusts for existing key before re-adding
  • checkData() unhandled rejection: void this.checkData() swallowed promise rejections; now wraps in .catch() with error emission
  • handleExpired() stats underflow: stats could go negative when Keyv auto-expired items; now guards decrements behind key existence check
  • checkData() Map mutation: iterating _ttls while deleting entries; now snapshots entries before iterating

Test plan

  • All 147 tests pass (66 new tests added)
  • 100% statement and line coverage
  • Lint passes clean (biome)
  • Full code review performed with 5-angle analysis and verification

https://claude.ai/code/session_01R74MUq37AtZmGxxoKPiHDt


Generated by Claude Code

…etTtl, flushAll, events, and useClones

Add missing functionality to NodeCacheStore to bring it closer to parity with NodeCache:
- keys() and has() for key inspection with expiration-aware checks
- getTtl() to inspect a key's expiration timestamp
- flushAll() that clears data, resets all stats, and emits a "flush" event
- Events: "set", "del", "expired", "flush" emitted on corresponding operations
- useClones option for deep-cloning values via structuredClone on get/set
- checkperiod option for interval-based expired item detection
- deleteOnExpire option to control automatic deletion of expired items
- close() and getIntervalId() for interval lifecycle management

Also fixes several bugs found during code review:
- setTtl() falsy-zero: `if (item)` replaced with `if (item !== undefined)`
- mdel() unconditional stats: now delegates to del() for proper guarding
- startInterval() timer leak: calls stopInterval() before creating new timer
- set() overwrite double-counting: adjusts stats for existing key before re-adding
- checkData() unhandled rejection: wraps async call in .catch() with error emission
- handleExpired() stats underflow: guards decrements behind key existence check
- checkData() Map mutation: snapshots entries before iterating

https://claude.ai/code/session_01R74MUq37AtZmGxxoKPiHDt
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the NodeCacheStore with support for cloning cached items, active background expiration checks via intervals, event emissions for cache operations, and several new utility methods like keys(), has(), getTtl(), and flushAll(). Feedback focuses on critical concurrency issues, such as a race condition in handleExpired that could lead to silent data loss, and another race condition in set that can cause double-counting of stats. Additionally, suggestions are provided to filter out expired keys in the keys() method and to parallelize sequential operations in mget, mdel, and mset using Promise.all for better performance.

Comment thread packages/node-cache/src/store.ts
Comment thread packages/node-cache/src/store.ts Outdated
Comment thread packages/node-cache/src/store.ts
Comment thread packages/node-cache/src/store.ts Outdated
Comment thread packages/node-cache/src/store.ts
Comment thread packages/node-cache/src/store.ts
@codecov
Copy link
Copy Markdown

codecov Bot commented May 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (1508695) to head (f6f8fc7).

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #1643    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files           26        26            
  Lines         2497      2608   +111     
  Branches       554       579    +25     
==========================================
+ Hits          2497      2608   +111     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98bdccf604

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/node-cache/src/store.ts
Comment thread packages/node-cache/src/store.ts
Comment thread packages/node-cache/src/store.ts Outdated
Comment thread packages/node-cache/src/store.ts
Comment thread packages/node-cache/src/store.ts
jaredwray and others added 3 commits May 26, 2026 09:54
…atures

Document new NodeCacheStore options (useClones, checkperiod, deleteOnExpire),
methods (keys, has, getTtl, flushAll, close, getStats, flushStats), and events
(set, del, expired, flush, flush_stats) with usage examples and option tables.

https://claude.ai/code/session_01R74MUq37AtZmGxxoKPiHDt
- Add race condition guard in handleExpired with double isExpired check
  before and after async Keyv get to prevent deleting refreshed keys
- Move _keys.add before async operations in set() to prevent concurrent
  set calls from both seeing isOverwrite=false
- Emit expiration timestamp in set event to match NodeCache contract

https://claude.ai/code/session_01R74MUq37AtZmGxxoKPiHDt
Comment thread packages/node-cache/src/store.ts Outdated
Parallelize batch operations for better performance with remote Keyv
backends. Each individual set/get/del call adds to _keys synchronously
before its first await, so unique keys (the common case) are safe from
race conditions. Stats increments are atomic within each post-await
microtask block.

https://claude.ai/code/session_01R74MUq37AtZmGxxoKPiHDt
@jaredwray jaredwray merged commit bf3ea48 into main May 26, 2026
12 checks passed
@jaredwray jaredwray deleted the claude/friendly-bohr-veUyM branch May 26, 2026 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants