Task Scheduling(NestJs)

koreanhole·2021년 2월 17일
0

UOS공지사항

목록 보기
1/2

Intro

현재 UOS공지사항의 백엔드 시스템을 nestjs로 변경하는 작업을 진행중이다.

UOS공지사항에서 가장 핵심적인 부분이 공지사항의 스크래핑이라고 볼 수 있다.

공지사항의 스크래핑은 그 특성상 주기적으로 반복해야하는 작업이다.

nestjs에서 특정 서비스 로직을 어떤 방법으로 주기적으로 실행할 수 있는지 정리해보았다.

Cron

cron은 작업을 고정된 시간, 날짜, 간격에 주기적으로 실행하는데 사용되는 표준 Unix 유틸리티이다.

nestjs는 node-cron 패키지를 사용하여 cron job을 지원한다. node-cron은 OS레벨에서 작동하는 cron은 아니며 cron의 기능을 모방하는 패키지이다.

Class Decorator를 통한 declarative방식과 nestjs의 SchedulerRegistry API를 통한 dynamic방식으로 cron을 사용할 수 있다.

declarative cron jobs

nestjs의 @Cron decorator에 첫번째 인수로 표준 cron패턴을 입력한다.

표준 cron패턴은 Asterisk(ex. *), Range(ex. 1-3, 5) 그리고 Step(ex. */2)으로 이루어진다.

cron 패턴 string은 총 6자리로 이루어져 있고 각 자리마다의 의미는 다음과 같다.

* * * * * *
| | | | | |
| | | | | day of week
| | | | month
| | | day of month
| | hour
| minute
second (optional)

만약에 매일 오전 9시부터 오후 5시까지 30분마다 Cron job을 실행하고 싶다면 cron패턴은 다음과 같다.

@Cron('0 */30 9-17 * * *')

크론 패턴을 뒤에서부터 읽어볼때 day of weekmonth 그리고 day of month* 로 표시되어 있으므로 job을 매일 반복적으로 실행하겠다는 의미가 된다.

hour9-17 로 표시되어 있으므로 9시 ~ 17시 사이에 job을 실행하겠다는 의미가 추가된다.

마지막으로 minute*/30 로 표시되어 있으므로 매 30분 마다 job을 실행한다.

결과적으로 '0 */30 9-17 * * *' 은 매일 오전 9시부터 오후 5시까지 30분마다 job을 실행한다.

nestjs의 @Cron 데코레이터에 두번째 인수로 추가적인 옵션을 전달할 수 있다.

전달가능한 옵션은 name timezone utcOffset 이 있다.

timezoneutcOffset 은 cron job의 실행을 위한 시간대 설정에 관한 옵션이다. 선택에 따라 둘 중 하나의 옵션을 전달하면 된다.

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

@Injectable()
export class NotificationService {
  @Cron('* * 0 * * *', {
    name: 'notifications',
    timeZone: 'Europe/Paris',
  })
  triggerNotifications() {}
}

dynamic cron jobs

@nestjs/schedule 모듈의 dynamic API를 통하여 declarative cron job을 관리하거나 새롭게 cron job을 생성할 수 있다.

SchedulerRegistry API를 통해 CronJob인스턴스에 접근하려면 SchedulerRegistry를 주입해야한다.

constructor(private schedulerRegistry: SchedulerRegistry){}

새로운 cron job 생성

this.schedulerRegistry.addCronJob(name, new Cron(cronExpression, callback));

cron job 삭제

this.schedulerRegistry.deleteCronJob(name);

cron job 가져오기

const job = this.schedulerRegistry.getCronJob(name)

getCronJob(name) 으로 가져온 cronjob 오브젝트는 다음과 같은 작업을 수행할 수 있다.

  • stop() : 계획되어있는 job을 중단시킨다.
  • start() : 멈춘 job을 재개한다.
  • setTime(time: CronTime) : job을 잠깐 멈춘 후 새로운 시간을 설정하고 다시 job을 시작한다.
  • lastDate() : 마지막 job이 실행된 시각을 string으로 반환하는 함수이다.
  • nextDates(count: number) : 다가오는 job의 실행 시각을 count만큼의 크기를 갖는 배열로 반환한다.

Intervals

특정 task를 일정시간 간격으로 반복적으로 실행하기 위해 사용한다.

interval역시 nestjs에서 declarative, dynamic한 방식으로 사용할 수 있으며 JavaScript의 setInterval() 함수가 기반이 된다.

declarative intervals

@Interval('notifications', 10000)
handleInterval() {
  this.logger.debug('Called every 10 seconds');
}

dynamic intervals

const interval = this.schedulerRegistry.getInterval('notifications');
clearInterval(interval);

JavaScript에서의 setInterval

setInterval(callback, delay, args...) 는 delay 마다 콜백을 주기적으로 실행한다.

만약에 delay를 100ms로 설정했는데 callback 함수의 실행이 100ms보다 오래걸리면 어떻게 될까?

interval은 delay없이 콜백함수를 바로바로 실행한다.

Timeouts

특정 task를 일정 시간이 지난 후에 단 한번 실행하기 위해 사용한다.

declarative timeouts

@Timeout('notifications', 5000)
handleTimeout() {
  this.logger.debug('Called once after 5 seconds');
}

dynamic timeouts

const timeout = this.schedulerRegistry.getTimeout('notifications');
clearTimeout(timeout);

JavaScript에서의 setTimeout

setTimeout(callback, delay, args...) 은 delay 후 callback을 딱 한번 실행한다.

하지만 중첩된 setTimeout을 사용하면 callback을 반복적으로 실행할 수 있다.

setInterval과 중첩된 setTimeout의 차이점이라면 setInterval과 달리 setTimeout은 콜백 사이의 최소 delay를 보장해준다는 것이다.

참고자료

Documentation | NestJS - A progressive Node.js framework

setTimeout과 setInterval을 이용한 호출 스케줄링

https://www.notion.so/10-setTimeout-setInterval-b71a02545c8f44e6afcb6b685d675cd3

0개의 댓글