이전 이메일 코드인증 포스팅을 보면 이메일 인증을 위해 코드를 DB에 저장하였다.
하지만 DB에 저장한 코드는 일회용 인증을 위한 코드데이터이며, 만료시간을 컬럼화 하여 저장하였다. 따라서 DB에 쓸대없이 만료시간이 지나거나 이미 사용된 코드의 데이터가 남아서 용량을 차지하게 된다.
어쨋든 코드를 발송하고 해당 코드를 비교하기 위해 어딘가 저장해야한다. 이러한 일회성 데이터 저장은 어떻게 해야할까 고민하면
캐시메모리에 TTL설정으로 자동 휘발되도록 데이터를 넣어놓고, TTL이 지나가기 전에 인증을 진행하도록 사용자에게 요청한다.
DB에 저장하고 인증을 진행한다. 이 경우 DB에 잔재 데이터가 남기 때문에 지워줘야한다.
1번 방식은 이전에 캐시메모리 포스팅에서 사용해 보았으니 2번 방법을 사용해보자.
2번 방식에 대해서 간단하게 생각해 보면 "만약 코드를 인증처리 하였을 때 바로 DB에서 인증된 코드를 삭제한다."라고 결론 지을 수도 있다.
하지만 인증번호는 이메일로 전송했는데 사용자가 이메일 인증완료를 위한 요청을 하지 않게 된다면? 해당 데이터는 그냥 DB에 잔존하게 되어 남게된다.
이러한 불상사를 막기위해 DB에 코드를 저장할 때 만료시간을 기록하고 해당 만료시간이 지난 데이터를 주기적으로 삭제하는 로직인 생각해 보았다.
NestJS에서는 주기적으로 동작할 수 있는 ScheduleModule을 제공한다. NestJS공식 홈페이지의 Task Scheduling 페이지에서 간단하게 사용방법을 알 수 있다.
npm을 통해 스케쥴모듈과 타입구분을 위한 @types/cron을 설치해 준다.
$ npm install @nestjs/schedule
$ npm install @types/cron
아마 NestJS의 스케쥴모듈은 node-cron라이브러리를 기반으로 만들어 진것 같다.
다음 app모듈의 Imports란에 ScheduleModule.forRoot()
를 추가해주면 ScheduleModule을 사용할 수 있다.
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
@Module({
imports: [
ScheduleModule.forRoot()
],
})
export class AppModule {}
다음 원하는 곳에서 @Cron 데코레이터를 사용하여 동작시킬 수 있다.
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');
}
}
@Cron데코레이터에 들어가는 인자인 문자열의 의미는 다음과 같다.
Cron데코레이터 인자 문자열의 샘플
인자 | 의미 |
---|---|
* * * * * * | 매초 마다 |
45 * * * * * | 매분 45초가 될때 마다 (1분45초, 2분45초 ...) |
0 10 * * * * | 매 시간 10분 00초가 될때 마다 (1시10분, 2시10분 ...) |
0 /30 9-17 * * | 오전5시~오후9시까지 매30분 간격으로(5시30분, 6시, 6시30분 ...) |
0 30 11 * * 1-5 | 월요일~금요일 오전11시30분 마다 |
이제 저장된 코드를 지우는 로직을 작성해 보자.
//만료시간이 지난 데이터를 2시간마다 자동삭제
@Cron('0 0 */2 * * *')
async deleteExpiredCodeAuto() {
const thisTime = new Date();
const existExpiredCodeDate = await this.authenticationRepository.find({
where: { expiration: LessThan(thisTime) },
});
if (existExpiredCodeDate)
await this.authenticationRepository.delete({
expiration: LessThan(thisTime),
});
}
만료시간이 현재시간보다 작은, 즉 현재시간 기준으로 만료시간이 지난 데이터들을 뽑아와서 delete하는 로직을 @Cron데코레이터를 이용해 매 2시간마다 지워지도록 작성하였다. 만료시간을 1시간으로 설정해 두었기 때문에 만약 삭제시간을 1시간으로 똑같이 맞춘다면, 59분에 만들어서 1분후 코드를 인증하려는 사용자는 데이터가 없어져서 인증이 불가능하게 될 것이다. 따라서 2시간의 텀으로 해당 로직을 작성하였다.