문제 발생
수강생이 강의 신청을 하면 강의일로부터 하루 전에 예약 메시지를 보내야 한다.
수강생이 많을수록 예약 메시지도 많아진다.
node-cron으로 스케줄러를 통해 강의일로부터 하루 전에 예약 메시지를 보내고 있었는데 애플리케이션 단에서 수정을 하게 됐다.
서버에서 도커로 돌아가던 애플리케이션을 다운시키고 이미지를 풀 받은 다음 다시 올렸다.
그러자 예약 메시지들이 오지 않는다.
왜일까?
그건 제목에도 적었듯이 node-cron이 메모리에 스케줄러를 저장시키기 때문이다.
즉, 도커를 다시 시작하자 메모리가 리셋되면서 스케줄러가 없어진거다 🤯🤯🤯
해결법으로 Redis에 저장하자
꼭 Redis가 아니어도 된다.
다른 데이터베이스를 사용해도 되는데 난 Redis를 사용했다.
그렇다면 Redis에 무엇을 저장해야할까?
복원할 때 필요한 스케줄러 시간과 스케줄러 코드 자체를 저장하면 된다고 생각했다.
틀렸다 ㅋ
스케줄러 코드 자체를 Redis에 저장하는 것은 보안과 용량에 문자가 있다.
정답은 스케줄러 코드가 돌아갈 수 있는 메타데이터들만 Redis에 저장하는 것이다.
그렇다면 코드는?
애플리케이션에 복원 코드를 따로 둬야 한다.
// Redis 저장 하는 함수
const setupAndSaveCronJob = (name, metadata, jobFuncion) => {
// 스케줄러 작업 설정
const job = cron.schedule(metadata.time, jobFuncion, {
scheduled: true,
timezone: 'Asia/Seoul',
});
// 스케줄러 설정을 Redis에 저장
client.set(`testOne:${name}`, JSON.stringify(metadata), err => {
if (err) {
console.log(`Error saving job ${name} to Redis:`, err);
} else {
console.log(`Job ${name} saved to Redis`);
}
});
return job;
};
// 스케줄러 작업 설정
setupAndSaveCronJob(name, metadata, async () => {
(스케줄러 코드 작성)
(복원 코드와 동일)
// 스케줄러가 잘 되었을 경우 레디스에서 삭제
client.del(`smsTimeOne:${this.param[3].value}`);
});
코드를 이렇다.
여기에서 신경 써줘야 하는 건 스케줄러가 잘 되었을 경우 레디스에서 삭제하는 것이다.
레디스에서 삭제를 안 할 경우 계속해서 살아있기 때문에 애플리케이션을 다시 시작할 때 문제가 발생할 수 있다.
메타데이터의 경우 복원 코드에서 쓰일 것을 생각해서 객체에 저장하면 된다.
그럼 인제 복원을 시켜보자.
복원시키자
const redis = require('redis');
export const client = redis.createClient({
url: process.env.REDIS_URL,
password: process.env.REDIS_PASSWORD,
});
client.connect();
client.on('connect', () => {
console.log('Redis client connected');
});
client.on('error', err => {
console.error('Redis client could not connect:', err);
client.quit();
});
애플리케이션 최상단 파일(대체로 app.ts)에 Redis 기본 셋팅을 해준다.
client.on('ready', async () => {
console.log('redils ready!');
// Redis에서 스케줄링 정보 불러오기
const keys = await client.keys('testOne:*');
for (const key of keys) {
const jobDataStr = await client.get(key);
const jobData = JSON.parse(jobDataStr);
// 스케줄러 작업
cron.schedule(
jobData.time,
async () => {
console.log('cron.schedule: ', jobData.time);
(위에서 작성한 코드와 동일한 복원코드 작성)
// 스케줄러 완료시 해당 데이터 삭제
client.del(key);
},
{
scheduled: true,
timezone: 'Asia/Seoul',
},
);
}
});
복원코드에선 Redis에 있는 모든 데이터를 동일한 key로(=textOne:*) 분기를 타서 반복문으로 돌아 스케줄러 작업을 다시 해준다.
이렇게 하면 날아간 스케줄러를 다시 똑같이 작업해줄 수 있다.
여기에서도 스케줄러 완료시 해당 Redis 데이터를 삭제 해야한다.
혹시 여기에서 복원해야하는 코드가 n개 있다면 함수화해서 예쁘게 작성하시길.
fin.
'Back Side > Module' 카테고리의 다른 글
[dayjs] JavaScript Date 객체는 불변성을 지켜주기 않는다 + dayjs의 필요성 (0) | 2023.11.01 |
---|---|
[Date] UTC to KST - 우당탕탕 요란스러운 여정기 (0) | 2022.12.07 |
댓글