@eeeasycode/request-cache
v0.0.3
Published
A Request-Scoped Cache module for NestJS using AsyncLocalStorage. Prevent duplicate method calls within a single HTTP request.
Maintainers
Readme
request-cache
NestJS 애플리케이션을 위한 Request-Scoped(요청 범위) 캐시 모듈입니다. 하나의 HTTP 요청 내에서 발생하는 **중복된 메서드 호출(API 요청, DB 조회 등)**을 방지하여 성능을 최적화합니다.
⚠️ 문제 상황 (Problem)
서비스에서 비즈니스 로직을 작성하다 보면, 하나의 요청을 처리하는 동안 동일한 데이터를 여러 곳에서 조회하는 경우가 빈번합니다.
// Controller
@Get('/me')
async getMyInfo() {
const user = await this.userService.getUser(1); // DB 조회 1
const usage = await this.usageService.getUsage(1); // 내부적으로 getUser(1) 또 호출 (DB 조회 2)
const billing = await this.billingService.getBilling(1); // 내부적으로 getUser(1) 또 호출 (DB 조회 3)
return { user, usage, billing };
}- 문제점:
getUser(1)이 한 요청 내에서 3번이나 호출되어 불필요한 DB 부하와 응답 지연이 발생합니다. - 기존 해결책(Redis 등): TTL 기반 캐시는 "요청 간 격리"가 안 되어, 실시간성이 중요한 데이터에 쓰기 어렵습니다.
- Request Scope Injection: NestJS의
Scope.REQUEST를 쓰면 인스턴스가 매번 생성되어 성능 오버헤드가 큽니다.
✅ 해결 방안 (Solution)
@eeeasycode/request-cache는 **AsyncLocalStorage (ALS)**를 사용하여 **"요청 단위의 격리된 캐시 저장소"**를 제공합니다.
- Zero Config: 데코레이터 하나만 붙이면 끝입니다.
- High Performance:
Singleton스코프를 유지하므로 인스턴스 생성 오버헤드가 없습니다. - Safety: 요청 A의 캐시가 요청 B에 공유되지 않습니다. 완벽하게 격리됩니다.
🛠 동작 원리 (How it works)
- Middleware: 요청이 들어오면
AsyncLocalStorage를 이용해 비어있는Map저장소를 생성합니다. - Decorator & AOP:
@RequestCache가 붙은 메서드가 실행될 때, 자동으로 현재 요청의 저장소를 확인합니다. - Cache Hit/Miss
- 저장소에 결과가 있으면 → 메서드를 실행하지 않고 캐시된 값을 반환합니다.
- 없으면 → 메서드를 실행하고 결과를 저장소에 담습니다.
- Cleanup: 요청이 끝나면 저장소는 자동으로 가비지 컬렉션(GC) 됩니다.
🚀 사용 방법 (Usage)
1. 설치
npm install @eeeasycode/request-cache
# or
pnpm add @eeeasycode/request-cache2. 모듈 등록
AppModule에 RequestCacheModule을 등록합니다.
import { Module } from '@nestjs/common';
import { RequestCacheModule } from '@eeeasycode/request-cache';
@Module({
imports: [RequestCacheModule.forRoot()],
})
export class AppModule {}3. 데코레이터 적용
캐싱하고 싶은 Service, Repository 메서드에 @RequestCache를 붙입니다.
import { Injectable } from '@nestjs/common';
import { RequestCache } from '@eeeasycode/request-cache';
@Injectable()
export class UserService {
// 이 메서드는 한 요청 내에서 파라미터(id)가 같으면 딱 1번만 실행됩니다.
@RequestCache('user-data')
async getUser(id: number) {
console.log('DB 조회 수행...'); // 첫 호출에만 찍힘
return this.userRepo.findOne(id);
}
}📝 License
MIT
