Nest.js Interceptor 응답 캐싱, timeout

이건선·2023년 6월 23일
0

Node.js

목록 보기
31/32

응답 캐싱


import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { Observable, of } from 'rxjs';
import { tap, map } from 'rxjs/operators';

@Injectable()
export class CacheInterceptor implements NestInterceptor {
  private readonly cache = new Map();

  intercept(
    context: ExecutionContext,
    next: CallHandler<any>,
  ): Observable<any> | Promise<Observable<any>> {
    const key = context.getHandler().name;
    const cacheValue = this.cache.get(key);
    const now = Date.now();

    if (cacheValue) {
      if (Date.now() < cacheValue.expirationTime) {
        console.log('in?');
        console.log(this.cache.get(key));
        console.log(`Execution time: ${Date.now() - now}ms`);
        return of(cacheValue.data);
      }
      this.cache.delete(key);
    }

    return next.handle().pipe(
      tap((data) => {
        const expirationTime = Date.now() + 1000 * 60 * 5;
        this.cache.set(key, { data, expirationTime });
        console.log(`Execution time: ${Date.now() - now}ms`);
      }),
    );
  }
}

Interceptor를 이용한 캐싱은 메모리 내에 데이터를 저장합니다. 이 방법은 간단하고 빠르지만, 서버가 재시작되거나, 메모리가 해제되면 캐시된 데이터는 사라집니다. 또한 이 방식은 동일한 애플리케이션 인스턴스 내에서만 캐시가 유지됩니다. 따라서 분산 시스템이나 다중 서버 환경에서는 효과적이지 않을 수 있습니다.

Redis를 사용한다면 영구적인 스토리지를 제공하므로 서버가 재시작되거나 메모리가 해제되더라도 데이터가 유지됩니다. 또한, Redis는 네트워크를 통해 접근할 수 있으므로, 다양한 서버나 애플리케이션 인스턴스 간에 데이터를 공유할 수 있습니다. 이는 분산 시스템이나 클러스터링 환경에서 매우 유용합니다.

Interceptor와 Redis를 함께 사용해서 Interceptor를 사용하여 요청과 응답을 관리하고, 실제 캐싱 작업은 Redis와 같은 데이터베이스에 위임할 수 있습니다. 이렇게 하면 Interceptor의 기능성과 Redis의 확장성을 동시에 활용할 수 있습니다.

타임아웃 설정


import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable, throwError, TimeoutError } from 'rxjs';
import { timeout, catchError } from 'rxjs/operators';

@Injectable()
export class TimeoutInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next
      .handle()
      .pipe(
        timeout(5000), // 5초가 지나면 타임아웃 에러 발생
        catchError(err => {
          if (err instanceof TimeoutError) {
            return throwError(new Error('Timeout has occurred')); // 타임아웃 에러를 캐치하고 대체 에러를 반환
          }
          return throwError(err); // 그 외의 에러는 그대로 반환
        }),
      );
  }
}

profile
멋지게 기록하자

0개의 댓글