Taming Cache Stampede in NestJS with RedisX
Cache stampede, or the thundering herd problem, is that pesky issue when a cache expires, and suddenly, your database gets bombarded by a swarm of requests. Not fun. In NestJS, there's a nifty way to tackle this using NestJS RedisX.
What's the Deal with Cache Stampede?
Imagine this: your app’s cache entry expires. Every request that comes in wants to hit the database at the same time. Chaos, right? The trick here is to make sure only one request actually goes through to the database, and the rest just chill until the first request updates the cache.
Enter NestJS RedisX
NestJS RedisX is like a Swiss Army knife for Redis in NestJS. One of its coolest features? Built-in cache stampede protection.
Setting It Up
Let's see how to set this up and save your database from overload.
- Get the Packages First thing, install RedisX and the cache plugin:
npm install @nestjs-redisx/core @nestjs-redisx/cache
-
Configure Redis in Your AppModule
Use
RedisModule.forRootAsyncto set things up with async config (thanks toConfigService):
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisModule } from '@nestjs-redisx/core';
import { CachePlugin } from '@nestjs-redisx/cache';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
RedisModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
plugins: [
CachePlugin.registerAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
l1: { enabled: true, maxSize: 1000, ttl: 60 },
defaultTtl: config.get('CACHE_TTL', 300),
stampede: { enabled: true },
}),
}),
],
useFactory: (config: ConfigService) => ({
clients: {
host: config.get('REDIS_HOST', 'localhost'),
port: config.get('REDIS_PORT', 6379),
},
}),
}),
],
})
export class AppModule {}
-
Decorate Your Services with @Cached
Now, slap the
@Cacheddecorator on your service methods that fetch data:
import { Injectable } from '@nestjs/common';
import { Cached } from '@nestjs-redisx/cache';
@Injectable()
export class ProductService {
@Cached({ key: 'product:{0}', ttl: 3600, stampede: { enabled: true } })
async getProduct(id: string): Promise<Product> {
return this.db.findProduct(id);
}
}
The Magic Behind It
With the @Cached decorator and the stampede option enabled, your app ensures that only one request hits the database. The rest wait their turn, and everyone gets their data once the cache is updated. It’s like a well-behaved queue at the supermarket checkout.
NestJS RedisX doesn't just handle cache stampedes. It's a full-on toolkit integrating Redis with features like distributed locks, rate limiting, and observability tools. Dive deeper into the official docs or check out the GitHub repo for more.
Top comments (0)