Node Schedule & PM2

QQQ
nodejs backend
Published in
7 min readMar 3, 2021

“매일 정기적으로 같은 시간에 같은 일을 실행시킨다.”

https://pixabay.com/ko/

개요

  • “node-schedule”가 무엇인지
  • Jobs and Scheduling
  • 시간 설정 방식
  • 서버 재실행에 자유로운 scheduling 구현
  • 멀티프로세스에서 중복되지않는 scheduling 구현

“node-schedule”가 무엇인지

Node Schedule 은 cron과 비슷하기도 하고 cron과 비슷하지만은 않은 스케줄러입니다. node-schedule은 “특정 작업”“특정 반복 조건”에 맞게 스케줄링(예약)할 수 있게 해줍니다.

node-schedule을 이용하기전에 확인하고 넘어갑시다.

상황에 따른 대체제 toad-scheduler/ cron

  • 특정한 시간에 작동하도록 예약하는 것이 아니라 특정 간격 마다 작동시키는 것을 원한다면(예를 들어, A함수를 5분마다 작동킨다.), toad-scheduler를 이용하는 게 더 좋을 것입니다.
  • Node 서버가 꺼져있는 상태에서는 작동하지 않습니다. Node 서버가 꺼져있을 때까지 작동하길 원한다면 OS에서 작동할 수 있는 cron을 이용하시기 바랍니다.

Jobs and Scheduling

node-schedule에서 예약하려는 모든 일들을 "Job" 객체라고 합니다. 직접 job들을 만들 수 있고, schedule() 함수를 이용하여 시간을 설정합니다.

다른 여러 노드 객체들처럼 Job 객체 또한 EventEmitter입니다. 그러므로 이벤트를 발생시켜 일을 처리하게 됩니다. 자주쓸 이벤트는 아래 4가지입니다.

  • run: 각각의 job이 실행된 후에 발생하는 이벤트.
  • scheduled: 각각의 job이 예약되었을 때의 이벤트.
  • canceled: 각각의 job이 취소되었을 때의 이벤트.
  • error: 각각의 job에 에러가 발생했을 때의 이벤트.

시간 설정 방식

Cron 스타일식 시간 설정

여섯개의 시간 설정 항목이 있고 띄어쓰기로 항목이 분리됩니다. *(별표) 표시는 all을 의미하므로 무작정 별표를 넣으시면 안되니 주의하세요.

example)


const schedule = require('node-schedule');
const job = schedule.scheduleJob('42 * * * *', function(){
console.log('The answer to life, the universe, and everything!');
});
// 매시간 42분에 예약하기. (eg, 19:42, 20:42)
const job = schedule.scheduleJob('0 17 ? * 0,4-6', function(){
console.log('Today is recognized by Rebecca Black!');
});

Date 스타일식 시간 설정

매우 특정한 시간에 작동시키길 원할 때 이용합니다.

const schedule = require('node-schedule');
const date = new Date(2012, 11, 21, 5, 30, 0);
const job = schedule.scheduleJob(date, function(){
console.log('The world is going to end today.');
});

재귀식 규칙 시간 설정 (Recurrence Rule)

반복적으로 규칙에 맞게 job을 실행시켜야 한다면 RecurrenceRule()을 이용하면 됩니다.

const schedule = require('node-schedule');const rule = new schedule.RecurrenceRule();
rule.minute = 42;
const job = schedule.scheduleJob(rule, function(){
console.log('The answer to life, the universe, and everything!');
});

타임존 또한 설정가능합니다.

rule.tz = 'ETC/UTC'

rule에 설정할 수 있는 값들입니다.

  • second (0–59)
  • minute (0–59)
  • hour (0–23)
  • date (1–31)
  • month (0–11)
  • year
  • dayOfWeek (0–6) Starting with Sunday
  • tz

서버 재실행에 자유로운 scheduling 구현:

“Node 서버가 재실행되더라도 예약된 작업들이 살아있어야 한다.”

기본적으로 node-schedule은 서버가 꺼지면 사라집니다. 이를 해결할 방법은 여러가지가 있습니다.

  1. cron: OS단에서 예약된 작업을 실행하기때문에 node 서버가 재부팅된 상태여도 예약된 작업들이 살아있습니다.
  2. agenda.js: 작업들을 DB(mongoDB)에 저장하여서 불러오기 때문에 서버가 꺼져도 예약된 작업들이 서버의 살아있음 유뮤 상관없이 작동합니다.
  3. node-schedule: 서버를 실행시키는 코드에 node-schedule 예약 코드를 넣어둡니다. db를 연결하거나, 서버에 필요한 것들을 실행시키는 코드(/src/index.js 파일)에 스케줄링코드까지 집어넣습니다. 그러면 매번 서버가 재실행될때마다 작업이 예약되므로 계속 유지할 수 있습니다.
    but 서버를 한개의 instance로만 실행시킬수는 없는 노릇입니다. 이 방식대로 하면 실행되는 모든 node instance에서 실행되므로 job이 중복되게 실행되는 문제가 발생합니다.
  4. pm2: pm2를 이용한다면 서버에 문제가 생겨 멈추어버렸을 때 알아서 다시 시작하게 됩니다. 그리고 특정 프로세스에만 scheduling을 설정할 수 있습니다.

멀티프로세스에서 중복되지않는 scheduling 구현:

“하나의 프로세서에서만 scheduling이 실행되어야만 한다.”

서버로 들어오는 요청을 하나의 프로세스에서 모두 처리하기는 힘듭니다. 그래서 cpu만큼 프로세스를 만들어 멀티 프로세스로 요청을 처리하게 됩니다. 보통 node로 서버를 구축할 때는 pm2를 이용하여 여러개의 프로세스를 관리하게 됩니다.

pm2 & node-schedule

pm2에서는 process마다 번호를 제공해줍니다. 그 번호를 이용하여 특정 process에게만 scheduling을 설정할수 있고, 하나의 프로세스에서만 예약된 작업이 실행되게 할 수 있습니다. node-schedule을 이용하며 아무런 설정도 하지 않는다면 여러 개의 프로세스에서 job을 실행하여 예상하지 못한 일이 발생할 수 있습니다.

pm2 — NODE_APP_INSTANCE

https://pm2.keymetrics.io/docs/usage/environment/#node_app_instance-pm2-25-minimum
위 링크를 들어가보시면 pm2 document 자체적으로도 NODE_APP_INSTANCE 변수를 scheduling에 이용하라고 합니다. 다른 이름으로 사용하고 싶다면, pm2.config.js에서 instance_var를 설정하시면 됩니다.

module.exports = {
apps : [{
name: 'appName',
script: 'src/index.js',
instance_var: 'INSTANCE_ID', // 편한 이름으로 설정하면 됩니다.
instance: 0,
exec_mode: 'cluster',
min_uptime: 5000,
max_restarts: 5,
args: '',
env:{
NODE_ENV:'production'
}
}],
};

그리고 이 변수를 이용하여 하나의 프로세서에서만 스케줄을 설정하도록 하면 됩니다.

// index.js~~if (process.env.INSTANCE_ID == 0) {
// schedule your job here.
}

pm2에서 첫번째 프로세스는 0이므로 첫번째에서만 scheduling해두면 job이 중복되어 실행되지 않게 됩니다. 참고stackoverflow

마무리

scheduling하는 것은 그리 어렵지않기 때문에 아무 것이든 사용해도 큰 문제가 되지 않습니다. 편하신 걸 이용하시기 바랍니다.

--

--