[NestJs] 태스크 스케줄링

Gmini.Y·2024년 3월 3일

1. @nestjs/schedule 패키지

주기적으로 동일한 작업을 처리해야할 때 태스크 스케줄링을 통해 만들수 있다. Node.js에는 크론 기능을 하는 여러 라이브러리가 있고 Nestsms node-cron을 통합한 @nestjs/schedule 패키지를 제공한다.

$ npm i --save @nestjs/schedule @types/cron   

태스크 스케줄링은 ScheduleModule을 사용한다. 이 모듈을 AppModule에서 바로 사용해도 되지만 별도 모듈인 BatchModule에 작성한다.

import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { TaskService } from './task.service';

@Module({
  imports: [ScheduleModule.forRoot()],
  providers: [TaskService],
})
export class BatchModule {}

2. 태스크 스케줄링을 선언하는 방식

2.1 크론 잡 선언 방식

크론 잡 선언 방식은 @Cron 데커레이터를 선언한 메서드를 태스크로 구현하는 방식이다.

import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';

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

  @Cron('* * * * * *', { name: 'cronTask' })
  handleCron() {
    this.logger.log('Task Called!');
  }
}

2.2 인터벌 선언 방식

@Interval 데커레이터를 사용하여 인터벌로 스케줄링을 할 수 있다.

import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';

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

  @Cron('* * * * * *', { name: 'cronTask' })
  handleCron() {
    this.logger.log('Task Called!');
  }

  @Interval('intervalTask', 3000)   // 앱 실행 후 3초 후에 처음 수행되며, 3초마다 반복
  handleInterval() {
    this.logger.log('Task Called!');
  }
}

2.3 타임아웃 선언 방식

앱이 실행된 후 태스크를 단 한번만 수행한다. @Timeout 데커레이터를 사용한다.

import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';

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

  @Cron('* * * * * *', { name: 'cronTask' })
  handleCron() {
    this.logger.log('Task Called!');
  }

  @Interval('intervalTask', 3000)   // 앱 실행 후 3초 후에 처음 수행되며, 3초마다 반복
  handleInterval() {
    this.logger.log('Task Called!');
  }
  
  @Timeout('timeoutTask', 5000)
  handleTimeout() {
    this.logger.log('Task called by timeout');
  }
}

3. 동적 태스크 스케줄링

앱 구동 중 특정 조건을 만족했을 때 태스크를 등록하도록 해보자. 이를 위해서는 태스크를 등록/해제할 방법이 필요하다. 동적 태스크 스케줄링은 SchedulerRegistry에서 제공하는 API를 사용한다.

import { Injectable, Logger } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';
import { CronJob } from 'cron';

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

  constructor(private schedulerRegistry: SchedulerRegistry) {
    this.addCronJob();
  }

  addCronJob() {
    const name = 'cronSample';

    const job = new CronJob('* * * * * *', () => {
      this.logger.warn(`run! ${name}`);
    });

    this.schedulerRegistry.addCronJob(name, job);

    this.logger.warn(`job ${name} added!!`);
  }
}

이 상태에서는 아무런 동작을 하지 않는다. 등록된 크론 잡을 스케줄링으로 동작시키고 중지하는 기능을 가진 컨트롤러를 추가해보자.

import { Controller, Post } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';

@Controller('batches')
export class BatchController {
  constructor(private scheduler: SchedulerRegistry) {}

  @Post('/start')
  start() {
    const job = this.scheduler.getCronJob('cronSample');

    job.start();

    console.log('start!! ', job.lastDate());
  }

  @Post('/stop')
  stop() {
    const job = this.scheduler.getCronJob('cronSample');

    job.stop();

    console.log('stop!! ', job.lastDate());
  }
}
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { TaskService } from './task.service';
import { BatchController } from './batch.controller';

@Module({
  imports: [ScheduleModule.forRoot()],
  providers: [TaskService],
  controllers: [BatchController],
})
export class BatchModule {}

본 포스트는 한용재 저자의 NestJS로 배우는 백엔드 프로그래밍을 기반으로 스터디하며 정리한 내용들입니다.

0개의 댓글