Skip to content

Client Side Caching #2947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,24 @@ of sending a `QUIT` command to the server, the client can simply close the netwo
client.destroy();
```

### Client Side Caching

Node Redis v5 adds support for [Client Side Caching](https://redis.io/docs/manual/client-side-caching/), which enables clients to cache query results locally. The Redis server will notify the client when cached results are no longer valid.

```typescript
// Enable client side caching with RESP3
const client = createClient({
RESP: 3,
clientSideCache: {
ttl: 0, // Time-to-live (0 = no expiration)
maxEntries: 0, // Maximum entries (0 = unlimited)
evictPolicy: "LRU" // Eviction policy: "LRU" or "FIFO"
}
});
```

See the [V5 documentation](./docs/v5.md#client-side-caching) for more details and advanced usage.

### Auto-Pipelining

Node Redis will automatically pipeline requests that are made during the same "tick".
Expand Down
97 changes: 97 additions & 0 deletions docs/v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,100 @@ await multi.exec(); // Array<ReplyUnion>
await multi.exec<'typed'>(); // [string]
await multi.execTyped(); // [string]
```

# Client Side Caching

Node Redis v5 adds support for [Client Side Caching](https://redis.io/docs/manual/client-side-caching/), which enables clients to cache query results locally. The server will notify the client when cached results are no longer valid.

Client Side Caching is only supported with RESP3.

## Usage

There are two ways to implement client side caching:

### Anonymous Cache

```javascript
const client = createClient({
RESP: 3,
clientSideCache: {
ttl: 0, // Time-to-live in milliseconds (0 = no expiration)
maxEntries: 0, // Maximum entries to store (0 = unlimited)
evictPolicy: "LRU" // Eviction policy: "LRU" or "FIFO"
}
});
```

In this instance, the cache is managed internally by the client.

### Controllable Cache

```javascript
import { BasicClientSideCache } from 'redis';

const cache = new BasicClientSideCache({
ttl: 0,
maxEntries: 0,
evictPolicy: "LRU"
});

const client = createClient({
RESP: 3,
clientSideCache: cache
});
```

With this approach, you have direct access to the cache object for more control:

```javascript
// Manually invalidate keys
cache.invalidate(key);

// Clear the entire cache
cache.clear();

// Get cache metrics
// `cache.stats()` returns a `CacheStats` object with comprehensive statistics.
const statistics = cache.stats();

// Key metrics:
const hits = statistics.hitCount; // Number of cache hits
const misses = statistics.missCount; // Number of cache misses
const hitRate = statistics.hitRate(); // Cache hit rate (0.0 to 1.0)

// Many other metrics are available on the `statistics` object, e.g.:
// statistics.missRate(), statistics.loadSuccessCount,
// statistics.averageLoadPenalty(), statistics.requestCount()
```

## Pooled Caching

Client side caching also works with client pools. For pooled clients, the cache is shared across all clients in the pool:

```javascript
const client = createClientPool({RESP: 3}, {
clientSideCache: {
ttl: 0,
maxEntries: 0,
evictPolicy: "LRU"
},
minimum: 5
});
```

For a controllable pooled cache:

```javascript
import { BasicPooledClientSideCache } from 'redis';

const cache = new BasicPooledClientSideCache({
ttl: 0,
maxEntries: 0,
evictPolicy: "LRU"
});

const client = createClientPool({RESP: 3}, {
clientSideCache: cache,
minimum: 5
});
```
3 changes: 3 additions & 0 deletions packages/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ export { GEO_REPLY_WITH, GeoReplyWith } from './lib/commands/GEOSEARCH_WITH';
export { SetOptions } from './lib/commands/SET';

export { REDIS_FLUSH_MODES } from './lib/commands/FLUSHALL';

export { BasicClientSideCache, BasicPooledClientSideCache } from './lib/client/cache';

10 changes: 8 additions & 2 deletions packages/client/lib/RESP/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,11 +314,17 @@ export interface CommanderConfig<
functions?: F;
scripts?: S;
/**
* TODO
* Specifies the Redis Serialization Protocol version to use.
* RESP2 is the default (value 2), while RESP3 (value 3) provides
* additional data types and features introduced in Redis 6.0.
*/
RESP?: RESP;
/**
* TODO
* When set to true, enables commands that have unstable RESP3 implementations.
* When using RESP3 protocol, commands marked as having unstable RESP3 support
* will throw an error unless this flag is explicitly set to true.
* This primarily affects modules like Redis Search where response formats
* in RESP3 mode may change in future versions.
*/
unstableResp3?: boolean;
}
Expand Down
Loading
Loading