스케쥴링도 대부분의 nestjs 기능처럼 decorator
로 쉽게 설정이 가능하다.
자세한 설정 방식은 공식문서에 잘 설명이 되어있다.
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
@Injectable()
export class TasksService {
private readonly logger = new Logger(TasksService.name);
@Cron('45 * * * * *')
handleCron() {
this.logger.debug('Called when the current second is 45');
}
}
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
@Injectable()
export class TasksService {
private readonly logger = new Logger(TasksService.name);
@Cron(CronExpression.EVERY_30_SECONDS)
handleCron() {
this.logger.debug('Called every 30 seconds');
}
}
다양한 옵션은 깃헙에서 확인이 가능하다.
타임존
같은 경우 특별히 지정을 해주어야지 지정한 시간대에 맞춰서 작동한다. 그렇지 않으면 UTC
기준으로 작동
참고 : nestJS-scheduling timezone
스케쥴이 필요한 이유는 매 자정에 제출하지 않은 goal들의 score
를 자동으로 만들어주기 위해서였다. 만일 score가 존재하지 않으면 chart
를 그릴 때 자료가 없어서 에러가 나오기 때문에 score가 0인 자료
를 매일 자정 전날
에 대해서 추가해주는 방식으로 스케쥴을 설정했다.
스케쥴을 돌렸는데 위와 같이 에러가 나왔다. 검색을 하다보니 이 문제는 해당 schedule이 다른 기능에 의존적
이기 때문에 발생했다. 처음 api를 만들때는 각 유저에 대해서 user
의 goal
을 찾고 그에 해당하는 score를 추가
하는 방식으로 진행했다. 이 방식으로 진행을 하게 되면 문제가 발생하는데 유저의 id를 가져오는 기능(useGuard)에 의존적
이기 때문에 위와 같이 id를 찾지 못한다는 에러가 나오게 되었다.
이것이 nestjs(대부분의 oop 프로그램)의 scope 개념에 기반한 것임을 알게 되었다.
useGuard
를 통해서 생성되는 것은 매 요청마다 새로이
생성되는 request scope
를 지니는 것이었고 이는 singletone
으로 처리해야 하는 cronjob
과는 맞지 않았다.
https://stackoverflow.com/a/61015839
그러면 싱글톤 방식을 유지하면서 schedule을 실행할 수 있는 방법은 무엇이 있었을까? 문제에 대해서 고민을 해본 결과 아무래도 schedule을 돌려서 제출되지 않은 골들에 대해 점수를 만들어내는 작업은 한 개인
의 identification
이후 일어나는 작업이 아니라 서버 관리자 차원
에서 이루어지는 작업인 것이 맞다고 생각을 했다.( 대부분의 서비스가 그렇게 작동을 하고 있다고 생각하는데... 게임 주간 보스 초기화하듯이)
별도의 api인 createScoreScheduled
을 만들었다. 이 api는 매 자정
에 발동하고 user 전체의 goal과 score 상황을 보고 제출되지 않은 goal에 대해서 점수 0인 score를 생성한다.
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT, { timeZone: 'Asia/Seoul' })
@ApiOperation({ summary: 'score 추가- 스케쥴' })
@Post('schedule')
createScoreScheduled() {
return this.scoreService.createScoreScheduled();
}
중간에 mongoDB 정책이 바꿔었는지는 모르겠는데 위와 같은 에러가 나왔다. (정확히는 cron의 문제는 아닌 것으로 확인)
그래서 에러에서 알려주는대로 현재 ip
를 whitelist
에 추가를 해주니 mongoDB에 데이터가 적절히 삽입이 될 수 있었다. (15:00
로 나오는 이유는 몽고db
는 utc 기준
으로 찍히기 때문에 24- 9 = 15
)
이후에 실제 배포한 ip도 등록을 해주어 해당 ip에서도 cron이 잘 작동하도록 설정해주었다. (mongo-atlas
- network- access
에서 확인 가능)