pg-smart-search
Guides

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 and implements Redlock-style deduplication.

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,
});

Cache Deduplication

In distributed environments, multiple instances might receive the same search query simultaneously. Without deduplication, all instances query the database at once, causing cache stampedes.

The RedisCacheProvider implements Redlock-style cache deduplication: only the first instance to acquire the lock queries the database, while the rest wait and serve the cached result once ready.

Cache Key Determinism & Page Compatibility

  • Deterministic Keys: To prevent duplicate database queries or mismatched cache states, search parameters (such as the dynamic filters object) 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 > 0 or data.length > 0 is true, ensuring that hot pages continue to cache seamlessly even when skipTotalCount is active.