스케줄 업무 자동화: Node-cron vs Node-schedule 비교 👊

filoscoder·2019년 12월 20일
29
post-thumbnail

🎯 본 포스팅은 필자기 Plating의 소프트웨어 엔지니어로 근무 중 작성 되었다. 현재 특정 고객사들은, 각 직원이 마감 시간전까지 원하는 메뉴를 주문하는 페이지가 제공되어있다 (React.js로 구현). 키친팀과 담당 운영자는 매일 마감시간에 맞춰서 주문페이지를 방문해 메뉴와 주문수량을 확인하여 조리와 기록을 진행한다. 현재 커스터마이징 된 telegram bot('Node로 간단한 Telegram bot 생성하기')으로 약속된 명령어를 입력하면 현재시각, 마감상태, 메뉴, 수량을 정보를 스크래핑하여 받아(Puppeteer 사용)볼 수 있도록 프로그램을 구현하였다.

(커스텀 bot에게 !bucket 명령어 결과 예시)

만약, 자동으로 정보 알림이 전송된다면? 🤔

번거롭게 주문 웹페이지를 접속하지 않아도 정보를 요청해서 받아도 되지만,
마감시간에 맞추어 그리고 주중(월-금)에만 정보를 전송하는 프로그램을 자동으로 호출 할 수 있다면 업무가 한결 편해질거라는 생각이 든다 🤩

가장 먼저 떠오르는 옵션: setTimeout & setInterval? 👀

주기적으로 어떠한 함수를 실행해야한다고 생각했을때 setTimeout()setInterval()함수를 결합하여 new Date()를 활용하여 간단하게 짜봐야겠다..
이런생각이 들었는데 2 가지 단점 때문에 외부 모듈을 사용하기로 결정했다:

  • 😖 지금 구현중인 프로그램의 코드 실행 flow를 제어하는데 어려움이 예상된다:
    • 스케줄된 특정시간 및 특정요일의 함수는 asyc await를 사용하는 스크래핑 프로그램이다, 비동기적으로 실행되는 setTimeout()setInterval() 함수를 이용했을때 실행 순서를 예측하는 어려움을 예상한다.
  • 😫 구현이 어렵다(귀찮다). 함수들의 본질적인 기능을 활용하여 새로운 미니-프로그램을 짜야한다.
    • setTimeout():특정 시간이 경과한 뒤에 특정 코드블록을 한번 실행한다.
    • setInterval(): 각각의 호출 간에 일정한 시간 간격으로 특정 코드블록을 반복적으로 실행한다.
    • 새로 짜야할 "미니-프로그램"은 호출할 프로그램과 밀접하게 엮이면서 보일러프레이팅('boilerplate' 뭐지?)이 불가능해질 것 같았다.
    • 🤬 나 아닌 다른분이 프로그램 코드를 접한다면 나의 귀를 아주 간지럽게 만들 것이다.
"Professor Butts and the Self-Operating Napkin" (1931) wiki

나를 괴롭히지 말자, 선하고 천재적인 엔지니어들의 작품들을 활용하자! 🤠

🤜 모듈을 활용하자: Agenda vs Node-cron vs Node-schedule?

검색과 리서치를 통해 추리게 된 3개의 모듈이 흥미로웠다: Agenda, Node-cron, Node-schedule.
3 모듈 다 '크론 형식'(Cron format 그림 참조)을 기반으로 핸드폰에서 알람 설정하듯이, 시간(시/분/초), 날짜(월/일), 요일(일~토)를 rule로 설정하여 실행할 함수를 지정해주면 아주 간편하고 확실하게 실행된다.

Cron이란?

Cron은 유닉스 같은 컴퓨터 운영 체제의 시간 기반 작업 스케줄러다. 소프트웨어 환경을 설정하고 유지하는 사용자는 Cron을 사용하여 고정 시간, 날짜 또는 간격으로 주기적으로 실행되도록 작업(명령 또는 셸 스크립트)을 예약한다. 일반적으로 시스템 유지보수 또는 관리를 자동화한다. Cron이라는 이름의 유래는 시간의 그리스어인 χρόνος (chronos)어원에서 왔다.

'크론 형식'(Cron format)

모듈 비교 📏

아래 비교를 테이블을 확인해보자 (기준: 2019년 12월 20일)

NPM Compare 참조

비교 결과 🎊

✖ 일단 Agenda는 탈락이다:

  • wiki 문서를 가지고 있고, 모듈을 유지하는 사람이 무려 5명이나 있고, 최근 리파지토리 수정이 심지어 어제였다 뭔가 활발하게 maintain 하는 모듈인것 같아서 관심이 갔다.
  • 서버사이드에서 스케줄화된 업무 짤때 강력하다, 하지만 mongoDB가 필수이다. 현재 프로그램은 AWSRDS를 사용하고 있다. nonSQL 기반 DB는 필요 없다.

🤛 Node-cron vs Node-schedule ?:

결론부터 말하면 최종적으로 Node-schedule을 사용하기로 결정했다. 🏆

관련 커뮤니티와 구글링을 꽤 깊이 해봤는데, 두 모듈을 집중적으로 비교한 정보도 없고, 명확하게 "ooo 때문에 oooo가 더 좋더라" 하는 글/댓글 또한 보기 힘들었다. 둘다 cron 형식 기반이여서 이해하기 어렵지 않고, 제공하는 함수 또한 매우 흡사하다.

📊 둘의 차이점을 기반으로 몇가지 아규먼트들을 나열해보겠다:
1. 다운로드 및 깃헙 구독자, Star 수: Node-schedule의 평균 일/주/월 다운로드 수가 거의 2배 이상이다. GitHub star 수는 무려 6배 이상이다. 구독자 또한 거의 100명이나 많다. 이러한 차이는 간단하게 '인기가 좋다'뿐만 아니라 많은 사람들이 인정하고 사용하는 만큼 그만큼의 Node-schedule 개발 커뮤니티와 레퍼런스가 많이 형성 되는 것이므로 추후에 도움을 얻을 수 있을 것이고 더욱 발전할 가능성을 열어둔다.
2. GitHub Issue건: 이부분에서는 Node-cronNode-schedule보다 40건이 낮다, 하지만 다운로드 star/fork 수를 비교하면 비례적으로 적다고 정의하기 애매하다.

최근 1년간 download 트랜드 repository stats (기준: 2019년 12월 20일)

NPM Trend 참조

  1. 유지보수: 위 테이블에 나와 있듯이 Node-schedule은 3명, Node-cron은 1명이 maintain 중이다. 그래도 명수가 많은 쪽이 대처하고 버전업 하는데 수훨하겠고 오래 지속될것이라고 예상한다.
  2. Object literal 문법: 두 모듈의 문법에서 유일하게 부각되는 차이는 Node-schedule에서 제공하는 Object literal 파라미터 전달이다. 아래에 코드에서 볼 수 있겠지만, cron 형식으로 스케줄 함수의 인자를 정의하는 것이 낯설다면 non-Cron 스타일인 직관적인 객체 형식으로 정의 할 수 있어 매우 직관적이다.
    // Cron style
    schedule.scheduleJob('30 11 * * 6', () => {})
    // non-Cron style
    schedule.scheduleJob({minute: 30, hour: 11, dayOfWeek: 6}, () => {})

    아쉽게도 Node-schedule은 wiki 문서는 제공하지 않지만 readme 파일에 있는 내용으로 충분하다고 생각한다.
    여기를 클릭하여 더 자세히 보기 (영문)

Node-schedule 여러 스타일 소개 💃🕺👯‍♀️

Cron 스타일로 작성된 매주 월 ~ 금 11시 30분 00초에 실행되는 작업이다.

// Runs every weekday (Mon ~ Fri)
// at 11:30
const j = schedule.scheduleJob('00 30 11 * * 1-5', () => {
    console.log('Cron-style Scheduling')
})

월 ~ 일 17시 45분 실행하려면 RecurrenceRule 객체 인스턴스 생성 후 dayOfWeek 속성에 해당 요일을 전달해야 하고 Range()를 통해 범위를 지정해야한다.

// Recurrence Rule Scheduling
// Sun ~ Sat 0 ~ 6
// 월 ~ 일 17시 45분 실행
const rule = new schedule.RecurrenceRule();
rule.dayOfWeek = [0, new schedule.Range(0, 6)];
rule.hour = 17;
rule.minute = 45;
const k = schedule.scheduleJob(rule, () => {
    console.log('Recurrence Rule Scheduling');
})

non-Cron 스타일, Object Literal 문법으로 손 쉽게 스케줄 설정하는 방법이다.

// Object Literal Syntax
// Sun ~ Sat 0~6
// every Saturday at 21:10
const job = schedule.scheduleJob({hour: 21, minute: 10, dayOfWeek: 6}, () => {
    console.log('Object Literal Syntax');
})

Date를 활용하여 시작 시간종료 시간을 지정하여 스케줄을 설정해봤다.

  // Set start time and End time
  const startTime = new Date(Date.now()+5000);
  const endTime = new Date(startTime.getTime()+5000);
  const m = schedule.scheduleJob({start: startTime, end: endTime, rule: '*/1*****'}, () => {
      console.log('Set startTime and endTime')
  })


🙏 긴 글 읽어주셔서 감사합니다, 비슷한 문제를 해결하시는데 도움이 됬셨기를 바라겠습니다!

오타, 잘못된 개념, 의견공유 언제든 환영입니다 🙆‍♂️

profile
Keep thinking code should be altruistic

10개의 댓글

comment-user-thumbnail
2019년 12월 20일

우와,,,,, 저는 디지털마케터이고 코딩에 대한 이해가 전혀 없는 사람인데 개발에 관심이 생겨 들어오게 되었어요!

근데 저같이 정말 코딩 1도 모르는 사람이 읽어도 이해가 쏙쏙 간다는게,,, 정말 대단하시네요 ㅜㅜ 많이 방문할게여!!! 좋은글 마니 남겨주세요🥺🔥❗️✌🏽

1개의 답글
comment-user-thumbnail
2020년 5월 12일

좋은 글 감사합니다!

1개의 답글
comment-user-thumbnail
2021년 2월 25일

와 제가 4시간은 할 고민을 10분으로 끝내주셨네요! 감사합니다 ㅠ

1개의 답글
comment-user-thumbnail
2021년 5월 10일

velog에 가입해서 댓글 남깁니다.
실무에서는 라이브러리 하나 도입하려면 이렇게 꼼꼼하게 사전 조사를 해야 되는군요!!!
토이 프로젝트 만들때 아무 생각 없이 node-cron 라이브러리를 선택해서 썼는데... 참 부끄럽네요.

1개의 답글
comment-user-thumbnail
2022년 3월 16일

혹시 maintainer 가 몇 명인지는 어떻게 알 수 있나요?

1개의 답글