[Javascript] 메일 발송 모듈과 스케쥴러 구현

정태호·2022년 12월 5일
2


node-schedule 패키지로 생성하는 스케쥴을 관리할 scheduler 모듈과 메일 전송 함수를 등록하여 전송 요청에 대한 처리를 대신 핸들링해줄 sendMoudule을 생성해보았다.

기존에 setTimeout 함수를 이용하려 했지만 리눅스의 cron을 사용하여 좀더 명확한 표현식으로 작동주기를 명시할 수 있는 node-schedule 패키지를 이용하기로 했다.

모듈을 구현할 때 다음과 같은 부분을 고려해 보았다.

scheduler

  • 등록되어 있는 스케쥴의 현재 상태와 작업 성공 여부를 확인할 수 있어야한다.
  • 상황에 따라 함수의 순차 실행의 보장을 보장해야한다.
  • 독립실행을 보장해야하는 함수등에 대한 처리가 가능해야한다.

sendModule

  • sendApi와의 의존성이 생기지 않도록 해야한다.
  • 모듈은 요청에 대한 자세한 내용에 대해서 알 필요가 없어야 한다.
  • 전송 요청에 대해서 비동기로 요청의 처리 결과를 반환할 수 있어야한다.
  • 실패한 요청에 대해서 조건에 따른 재발송 시도를 진행 해야 한다.

의 조건들을 충족 할 수 있도록 각 모듈을 구현해 보았다.

scheduler

registerScheduleJob 함수는 4개의 인자를 통해 스케쥴을 등록하게 된다.

  • cron표현식 : 등록 함수의 실행 주기를 지정
  • callback : 실제 실행할 함수
  • name : 생성될 node-scheduler 객체의 식별자
  • dependency : 해당 함수와 동시 실행이 불가능한 식별자를 지정

이때 creatScheduleCallback 함수를 통해 등록되는 함수를 랩핑하게 된다.

node-schedule을 통해 생성된 스케쥴러는 랩핑된 함수를 정해진 시간에 맞추어 실행시키게 되고 이때 jobExecStatus,cheduleJobList 변수에 저장된 정보를 조회 하여 바로 실행 가능한 상황인지를 확인한 후에 실제 함수를 실행시키도록 했다.

이러한 기능을 구현하기 위해 promise를 단독으로 생성하여 등록하고 함수의 종료 유무와 에러 발생시 해당 정보 저장이 완료되면 resolve 함수를 통해 fulfilled 상태로 변경시킬 수 있다.

promise를 상태정보로 등록시킴으로서 다음과 같은 이점이 있다고 판단했다.

  • promise.all() 을 통해 dependency가 설정된 함수의 microTaskQueue 대기
  • 자기 자신의 중복 실행 여부의 감시 및 순차 처리

dependency가 설정된 스케쥴러들의 promise가 resolve 처리 후 바로 실행 순서를 보장받을 수 있게 된다.

sendModule

이제 실제 실행될 함수가 수행된다.
필요한 테이블의 정보를 받아오고 필터링을 한 후에 메일 혹은 알림 발송이 필요한 유저에게 발송하기 위해 sendMoule의 sendInfoInsert 함수를 통해 발송 정보를 등록하게 된다.
이때 다음의 두개의 매개변수가 요구된다.

  • date : 발송하기 위한 정보를 담고 있는 변수(발송지,발송 타입 등)
  • contents : 발송할 내용 (html, 문구 등)

위의 두개의 인자만을 전달 받게 되며 해당 인자에 대한 유효성 체크를 등록된 sendApi의 validater에게 위임한다.
이때 sendModule은 데이터의 전달자 역할만을 수행하며, sendModule_interface에 의존성을 가진다.

sendModule_interface를 구현한 구현체인 validater를 통해 유효성 체크가 진행된 후, sendInfoQueue에 등록된다.

sendInfoQueue에 등록되는 이벤트를 기준으로 execSendApi가 실행되는데 이때 해당 함수의 단독 실행을 보장하기 위해 execSendApiProxy 함수를 두어 해당 함수의 호출을 핸들링할 수 있도록 했다.

이때 대량의 요청 처리시 다른 이벤트 처리를 블록킹하는 것을 막기 위해 Qeue의 요청을 하나씩 처리하며 자기 자신을 재귀호출 하도록 했다.

이때 중요한 점은 전송정보를 등록할때 반환된 promise는 전송 요청이 실패하더라도 reject되지 않고 조건에 따라 몇번의 재시도 후에 결과가 반환되는 점이다.

이를 위해 반환된 비어있는 promise의 resolve,reject 함수를 하위 스택 변수에 할당하였다.
그리고 이 함수는 requestHandler와 failRequestHandler에서 실행결과를 반환 하게 된다.

이렇게 반환된 정보를 기준으로 jobExecStstus가 가지고 있는 상태정보가 변화하게 되며 직전에 실행된 스케쥴이 실패했을 경우 해당 실패 정보가 등록된다.

최종적으로 scheduleJobsInfo 함수를 통해 스케쥴의 상태를 모니터링하고 실패 정보를 확인 할수 있다.

1개의 댓글

comment-user-thumbnail
2022년 12월 11일

좋은 글 잘 읽고갑니다. 저도 스케쥴링 시스템 구현할때 참고할게요~^^

답글 달기