Summary
The application uses a custom in-memory cache (userCache) with a manual pruning mechanism. The pruneUserCache() function is executed on cache misses and iterates over the entire Map to remove expired entries, resulting in an O(N) operation. Under high traffic or when the cache grows large, this can block the Node.js event loop and degrade application performance.
Affected File
Description
The application maintains a custom userCache and periodically removes expired entries by scanning the entire cache.
Since pruneUserCache() is invoked on cache misses, every cache miss may trigger a full traversal of the cache:
- Time Complexity: O(N)
- Event Loop Impact: High as cache size increases
- Scalability: Poor under heavy load
This approach does not scale well because Node.js executes JavaScript on a single-threaded event loop. Large synchronous iterations can delay request processing and increase response latency.
Steps to Reproduce
- Populate
userCache with a large number of entries.
- Generate repeated cache misses.
- Observe that
pruneUserCache() iterates over the entire cache on each miss.
- Monitor CPU usage and request latency under load.
- Notice increased event loop blocking as the cache grows.
Expected Behavior
Cache eviction should occur with minimal overhead and should not require scanning the entire cache on cache misses.
Actual Behavior
Every cache miss may trigger an O(N) cache pruning operation, causing unnecessary CPU usage and event loop blocking.
Performance Impact
- Increased request latency under load.
- Event loop blocking due to synchronous cache traversal.
- Reduced throughput as cache size grows.
- Poor scalability for applications with frequent cache misses.
Recommendation
Replace the custom cache implementation with a well-tested Least Recently Used (LRU) cache library such as lru-cache, which provides efficient cache eviction and expiration mechanisms.
Example:
const { LRUCache } = require('lru-cache');
const userCache = new LRUCache({
max: 1000,
ttl: 1000 * 60 * 5, // 5 minutes
});
Benefits include:
- Efficient cache eviction.
- Built-in TTL support.
- No manual pruning logic.
- Better performance under high load.
- Reduced event loop blocking.
References
Summary
The application uses a custom in-memory cache (
userCache) with a manual pruning mechanism. ThepruneUserCache()function is executed on cache misses and iterates over the entireMapto remove expired entries, resulting in an O(N) operation. Under high traffic or when the cache grows large, this can block the Node.js event loop and degrade application performance.Affected File
server.jsDescription
The application maintains a custom
userCacheand periodically removes expired entries by scanning the entire cache.Since
pruneUserCache()is invoked on cache misses, every cache miss may trigger a full traversal of the cache:This approach does not scale well because Node.js executes JavaScript on a single-threaded event loop. Large synchronous iterations can delay request processing and increase response latency.
Steps to Reproduce
userCachewith a large number of entries.pruneUserCache()iterates over the entire cache on each miss.Expected Behavior
Cache eviction should occur with minimal overhead and should not require scanning the entire cache on cache misses.
Actual Behavior
Every cache miss may trigger an O(N) cache pruning operation, causing unnecessary CPU usage and event loop blocking.
Performance Impact
Recommendation
Replace the custom cache implementation with a well-tested Least Recently Used (LRU) cache library such as
lru-cache, which provides efficient cache eviction and expiration mechanisms.Example:
Benefits include:
References
lru-cacheDocumentation: https://github.com/isaacs/node-lru-cache