728x90
- Task Scheduling 이란?
클라이언트에서 요청한 로직을 수행하는게 아닌, 서버에서 주기적으로 작업을 실행하는 것
- 메일링 리스트에 추천 영화 리스트를 주기적으로 보내줄때.
- 총 좋아요 갯수나 총 조회수처럼 특정 데이터를 주기적으로 업데이트할때.
- 주기적으로 데이터나 파일을 정리할때.
- 주기적으로 데이터 분석 리포트를 제작할때
- 주기적으로 데이터베이스를 백업할때
- Cron 배우기(강의를 많이 캡처해서 비공개 처리함)
https://springdream0406.tistory.com/196
- 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')
}
}
- NestJS Schedule 옵션
@Injectable()
export class NotificationService {
@Cron('* * 0 * * *', {
name: 'notifications',
timeZone: 'Europe/Paris',
})
triggerNotifications() {}
}
- SchedulerRegistry 함수
addCronJob(name: string, seconds: string) {
const job = new CronJob(`${seconds} * * * * *`, () => {
this.logger.warn(`time (${seconds}) for job ${name} to run!`);
});
this.schedulerRegistry.addCronJob(name, job);
job.start();
this.logger.warn(
`job ${name} added for each minute at ${seconds} seconds!`,
);
}
- stop() : 예정된 작업을 중지한다.
- start() : stop()이 실행된 작업을 재실행한다.
- setTime(time: Crontime) : 작업을 중지하고 새로운 주기를 생성하고 시작한다.
- lastDate() : 마지막으로 작업이 실행된 날짜를 반환한다.
- nextDate() : 다음으로 작업이 실행될 날짜를 반환한다.
- nextDates(count: number) : 다음으로 작업이 실행될 날짜들을 n개 반환한다.
여기까지 오면 너무 복잡해진다고 함. 보통 선언형에서 만족.
- 설치
yarn add @nestjs/schedule
- 잉여 파일(temp) 삭제 기능
// app.module.ts
imports: [
ScheduleModule.forRoot(),
],
// tasks.service.ts
@Injectable()
export class TasksService {
constructor() {}
@Cron('* * * * * *')
async eraseOrphanFiles() {
const files = await readdir(join(process.cwd(), 'public', 'temp'));
const deleteFilesTargets = files.filter((file) => {
const filename = parse(file).name;
const split = filename.split('_');
if (split.length !== 2) return true; // 삭제에 포함
try {
const date = +new Date(parseInt(split[split.length - 1]));
const aDayInMilSec = 24 * 60 * 60 * 1000;
const now = +new Date();
return now - date > aDayInMilSec;
} catch (e) {
return true;
}
});
// 병렬 - 리소스 부담 커짐
await Promise.all(
deleteFilesTargets.map((x) =>
unlink(join(process.cwd(), 'public', 'temp', x)),
),
);
// 직렬 - 시간 오래 걸림
// for (let i = 0; i < deleteFilesTargets.length; i++) {
// const fileName = deleteFilesTargets[i];
// await unlink(join(process.cwd(), 'public', 'temp', fileName));
// }
}
}
unlink() : 삭제
// common.module.ts
providers: [
TasksService,
],
- 좋아요, 싫어요 통계
유저들의 movie like/dislike를 movie에 바로바로 반영하지 않고, 1분에 한번씩 db 데이터 가져다가 update 시켜주는 방식
@Cron('0 * * * * *')
async calculateMovieLikeCounts() {
await this.movieRepository.query(
`
UPDATE movie m
SET "likeCount" = (
SELECT count(*) FROM movie_user_like mul
WHERE m.id = mul."movieId" AND mul."isLike" = true
)`,
);
await this.movieRepository.query(
`
UPDATE movie m
SET "dislikeCount" = (
SELECT count(*) FROM movie_user_like mul
WHERE m.id = mul."movieId" AND mul."isLike" = false
)`,
);
}
위 코드에서 Cron부분만 첨부함. (1분마다 실행)
update의 set에 서브쿼리를 넣어서 사용한게 신기함.
- SchedulerRegistry 함수 예시
constructor(
private readonly schedulerRegistry: SchedulerRegistry,
) {}
@Cron('* * * * * *', {
name: 'printer',
})
printer() {
console.log('print every seconds');
}
@Cron('*/5 * * * * *')
stopper() {
console.log('---stopper run---');
const job = this.schedulerRegistry.getCronJob('printer');
console.log('# Last Date');
console.log(job.lastDate());
console.log('# Next Date');
console.log(job.nextDate());
console.log('# Next Dates');
console.log(job.nextDates(5));
if (job.running) {
job.stop();
} else {
job.start();
}
}
위에서 언급했듯이. 웬만하면 쓰지 말아라. 쓰려면 모니터링 할 수 있는 거 마련해라.
https://fastcampus.co.kr/classroom/239666
커리어 성장을 위한 최고의 실무교육 아카데미 | 패스트캠퍼스
성인 교육 서비스 기업, 패스트캠퍼스는 개인과 조직의 실질적인 '업(業)'의 성장을 돕고자 모든 종류의 교육 콘텐츠 서비스를 제공하는 대한민국 No. 1 교육 서비스 회사입니다.
fastcampus.co.kr
728x90
'코딩 > Nest.js' 카테고리의 다른 글
Versioning (0) | 2024.10.27 |
---|---|
Logging (2) | 2024.10.26 |
Caching (2) | 2024.10.25 |
Multer (0) | 2024.10.25 |
Custom Decorator (1) | 2024.10.24 |