Caching
How to configure and use Memory and Redis caching providers in pg-smart-search for distributed environments.
Caching
Caching is critical for search performance. pg-smart-search comes with two built-in caching providers: an in-memory provider for single-instance apps, and a Redis provider for distributed production environments.
MemoryCacheProvider
The default provider. Stores cached results in the Node.js process memory. Fast, but isolated to a single instance.
Memory Leak Protection (v1.4.1+)
To prevent Out-Of-Memory (OOM) failures under heavy loads of unique queries, MemoryCacheProvider holds a default capacity limit of 10,000 entries and automatically evicts oldest cached keys using a Least Recently Used (LRU) eviction policy.
Furthermore, a background sweep timer daemon (defaulting to scan every 60,000ms) runs in the background to automatically clear expired keys from RAM.
import { TrigramSearchEngine, MemoryCacheProvider } from "pg-smart-search";
const engine = new TrigramSearchEngine(adapter, {
tableName: "products",
searchColumns: ["name"],
cacheProvider: new MemoryCacheProvider({
maxEntries: 10000, // Capacity limit
sweepIntervalMs: 60000, // RAM sweep frequency
}),
defaultTTL: 3600, // 1 hour
});RedisCacheProvider
For production environments running multiple Node.js instances, use the RedisCacheProvider. It ensures all instances share the same cache state — it's a thin get/set/delete/clear wrapper around your Redis client, with no distributed locking.
import Redis from "ioredis";
import { TrigramSearchEngine, RedisCacheProvider } from "pg-smart-search";
const redisClient = new Redis(process.env.REDIS_URL);
const engine = new TrigramSearchEngine(adapter, {
tableName: "products",
searchColumns: ["name"],
cacheProvider: new RedisCacheProvider(redisClient),
defaultTTL: 3600,
});import { createClient } from "redis";
import { TrigramSearchEngine, RedisCacheProvider } from "pg-smart-search";
const redisClient = createClient({ url: process.env.REDIS_URL });
await redisClient.connect();
const engine = new TrigramSearchEngine(adapter, {
tableName: "products",
searchColumns: ["name"],
cacheProvider: new RedisCacheProvider(redisClient),
defaultTTL: 3600,
});In-Flight Request Deduplication
The engine deduplicates concurrent identical searches within a single process: if the
same cache key is requested again while a search for it is already running, the second
caller attaches to the first one's in-flight promise instead of issuing a new query
(reference-counted, so cancelling one caller's abortSignal only aborts the shared query
once every attached caller has cancelled).
This is engine-level, not Redis-level — it works the same whether you're using
MemoryCacheProvider or RedisCacheProvider. What it does not do is coordinate
across separate Node.js instances: if two different processes miss the cache for the
same key at the same time, each will still query the database independently. There is no
distributed lock (Redlock or otherwise) preventing that.
Cache Key Determinism & Page Compatibility
- Deterministic Keys: To prevent duplicate database queries or mismatched cache states, search parameters (such as the dynamic
filtersobject) are sorted lexicographically before forming the unique cache key hash. - Deep Pagination Caching: In v1.4.1+, the engine has been optimized to save cached pages whenever either
total > 0ordata.length > 0is true, ensuring that hot pages continue to cache seamlessly even whenskipTotalCountis active.