Nest.js를 배워보자/8. NestJS에서 Cron, Scheduler 구현하기

Cron, Interval, Timeout 실습: 정기 작업 구현

_Blue_Sky_ 2025. 12. 2. 21:03
728x90

 

 


이전 주제에서 소개된 @nestjs/schedule 모듈의 세 가지 주요 데코레이터를 사용하여 실제 애플리케이션에서 활용할 수 있는 정기 작업 로직을 구현해 보겠습니다.

1. 🛠️ 스케줄 작업 서비스(TasksService) 생성

스케줄링 로직은 NestJS의 Provider인 서비스 클래스 내부에 정의되어야 다른 DI된 서비스(예: PrismaService, CacheService)를 주입받아 사용할 수 있습니다.

728x90

 
nest generate service tasks

2. ⏰ @Cron(): 특정 시각 작업 (DB 백업 예시)

@Cron() 데코레이터는 Cron 표현식을 사용하여 특정 시각에 정확히 한 번 실행되는 작업을 정의할 때 사용합니다. Cron 표현식은 초(Second)부터 시작하는 6자리 형식을 주로 사용합니다.

Cron 표현식 형식: 초 분 시 일 월 요일 (예: 0 30 2 * * * = 매일 2시 30분 0초)

// src/tasks/tasks.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';

@Injectable()
export class TasksService {
  private readonly logger = new Logger(TasksService.name);

  // 💡 매일 새벽 3시 0분 0초에 실행
  @Cron('0 0 3 * * *') 
  async handleDbBackup() {
    this.logger.warn('--- ⏳ 정기 DB 백업 작업 시작 ---');
    
    // 💡 실제로는 shell command 실행 또는 DB ORM을 이용한 덤프 작업 수행
    // await this.prisma.runBackupCommand(); 
    
    // 작업 완료 시 로깅
    this.logger.warn('--- ✅ DB 백업 완료 ---');
  }

  // 💡 매 5분마다 실행 (예: 10:05:00, 10:10:00, 10:15:00 ...)
  @Cron('0 */5 * * * *')
  handleEveryFiveMinutes() {
    this.logger.log('5분 간격으로 주요 지표를 집계합니다.');
  }
}

3. ⏱️ @Interval(): 반복 간격 작업 (캐시 업데이트 예시)

@Interval() 데코레이터는 지정된 시간(밀리초, ms) 간격으로 반복 실행되는 작업을 정의합니다. 이는 주기적인 데이터 동기화나 캐시 갱신 등에 유용합니다.

// src/tasks/tasks.service.ts (계속)
import { Interval } from '@nestjs/schedule';

// ...
@Injectable()
export class TasksService {
  // ...

  // 💡 10초(10000ms)마다 반복 실행
  @Interval(10000)
  async handleCacheUpdate() {
    // 💡 캐싱 서비스가 주입되었다고 가정
    // await this.cacheService.rebuildPopularItemsCache();
    
    this.logger.debug('인기 항목 캐시를 업데이트했습니다.');
  }
}
728x90

4. ⏳ @Timeout(): 단일 지연 실행 (초기화 작업 예시)

@Timeout() 데코레이터는 애플리케이션이 시작된 후 지정된 시간(밀리초, ms)이 지난 뒤 단 한 번만 실행되는 작업을 정의합니다. 이는 서버 초기화 후 특정 자원을 로드하는 등의 지연 작업에 사용됩니다. 

// src/tasks/tasks.service.ts (계속)
import { Timeout } from '@nestjs/schedule';

// ...
@Injectable()
export class TasksService {
  // ...

  // 💡 애플리케이션 시작 5초(5000ms) 후에 단 한 번 실행
  @Timeout(5000)
  handleTimeout() {
    this.logger.log('서버 시작 후 5초, 초기 설정 파일을 로드했습니다.');
    // 💡 초기 설정 파일을 DB에 로드하거나, 외부 서비스 연결을 최종 확인
  }
}

5. ⚠️ 주의 사항

  • 배포 환경: @nestjs/schedule은 단일 프로세스에서 작동합니다. 만약 NestJS 애플리케이션을 여러 인스턴스(클러스터, 멀티 서버)로 확장한다면, @Cron() 작업이 각 인스턴스마다 동시에 실행되는 문제가 발생할 수 있습니다.
  • 해결책: 다중 인스턴스 환경에서는 Redis Lock을 사용하거나, 외부의 독립적인 스케줄러(예: AWS EventBridge, Kubernetes CronJob, Bull Queue)를 사용하여 작업을 중앙에서 관리해야 합니다.
728x90