본문 바로가기
Programming

Cron 표현식으로 주중 오전 8시 표현하기

by LeeJ1Hyun 2024. 2. 18.

서비스를 운영하다 보면 특정 요일, 특정 시간에 동일한 작업을 수행해야 하는 일이 생긴다. 예를 들어 외부 Open API를 조회하여 가져온 값을 데이터 베이스에 저장하는 내부 API가 있다고 하자. 사람이 직접 매일 오전 8시에 호출해야 한다면 1년 365일 동안 한 번도 까먹지 않을 수 있을까? 만약 운영에 치명적인 영향을 주는 값이라면 어느 누구도 담당자가 되고 싶지 않을 것이다. 감사하게도 이를 대신해 주는 서비스들이 있다. 그중 하나가 AWS가 제공하는 Amazon EventBridge를 사용하여 AWS Lambda 함수를 실행하도록 하는 것이다.

 

AWS Lambda

Lambda는 서버리스 컴퓨팅 플랫폼이다. 서버리스 컴퓨팅이란 서버가 없다는 말이 아니고 서버의 별다른 설정 및 관리를 하지 않아도 된다는 의미이다. 그럼 이 관리는 누가 할까? 바로 AWS가 한다. 개발자는 오로지 코드만 작성하면 된다. Lambda에 실행시키고 싶은 함수를 작성하고 원할 때 실행할 수 있으며, 이를 람다 함수라고 부른다.

 

import { Handler } from 'aws-lambda';

export const handler: Handler = async (event, context) => {
    console.log('EVENT: \n' + JSON.stringify(event, null, 2));
    return context.logStreamName;
};

 

위 코드는 TypeScript로 작성한 AWS Lambda function handler 예시이다. handler란 Lambda가 이벤트(함수를 실행하게 하는 트리거)를 받았을 때 실행되는 함수이다. event는 람다 함수에 전달되는 이벤트의 정보, context는 람다 함수의 실행 컨텍스트 정보를 포함한다. 만약 이벤트가 HTTP 요청이라면, event에 실행하고자 하는 API의 uri, 파라미터 등에 대한 정보가 담겨 있는 것이다. AWS 공식 문서에서 제공하는 예시일 뿐이므로 log를 찍는 것 외에 원하는 로직을 작성하면 된다.

 

import { Handler } from 'aws-lambda';

export const handler: Handler = async (event, context) => {
    return await API를호출하는함수(event.uri);
};

 

대략 이렇게 작성할 수 있다. AWS console에서 직접 코드를 작성할 수도 있고, S3를 이용하여 업로드할 수도 있다.

 

EventBridge

Lambda는 이벤트에 의해 실행된다고 했다. API 게이트웨이를 이용하여 HTTP 요청을 보낼 수도 있고, S3 버킷에 의해 람다 함수를 실행할 수도 있다. 어떤 커뮤니티에 이미지가 포함된 게시글이 올라올 시 해당 이미지가 유해한 지 판단하는 기능이 있다고 하자. 유저가 올린 이미지가 S3 버킷에 업로드되면 유해 이미지인지 검사하는 람다 함수를 실행할 수 있다.

 

이러한 방법들 중 하나인 EventBridge에 대해 알아보자. 이름처럼 이벤트를 사용하여 애플리케이션 구성 요소를 서로 연결하는 서버리스 서비스이다. 쉽게 말하면 AWS에서 제공하는 서비스들의 이벤트를 중개하는 역할이다.

 

 

Lambda 입장에서는 EventBridge가 트리거가 된다. 트리거를 구성할 때 규칙 타입을 지정할 수 있는데 Event pattern, Schedule expression 둘 중에 선택할 수 있다. 우리가 원하는 특정 요일, 특정 시간에 람다를 실행하려면 Schedule expression을 사용해야 한다.

 

 

Schedule Expression을 선택하면 Cron or rate 표현식을 통해 박스를 채우라고 한다. 이중 Cron 표현식을 사용하여 월요일부터 금요일 주중 오전 8시에 트리거 되도록 하면 된다.

 

Cron Expression

Amazon EventBridge 공식 문서에서 제공하는 cron 표현식 규칙에 대해 살펴보자.

  • 필수 필드는 6개이며 각각 공백으로 구분
  • 순서대로 cron(분, 시간, 날짜, 월, 요일, 연도)
  • 와일드카드
    • , (쉼표)는 추가 값을 포함
    • -(대시)는 범위를 지정
    • *(별)은 필드의 모든 값을 포함
    • /(슬래시)는 증분을 지정
    • ?(물음표)는 any를 지정

예시를 보면서 이해하는 것이 빠르다. 아래 cron 표현식은 의미가 무엇일까?

 

cron(0 10 * * ? *)

 

 

순서대로 파악해 보자. 먼저 분은 0이므로 정각이라는 의미이다. 시간은 10이므로 오전 10시(UTC+0)이다. 날짜와 월은 *(별)이므로 1~31일, 1~12월 모두 포함된다. 고로 매일을 의미한다. 요일이?(물음표)인 이유는 제한 사항에 기재되어 있는 대로 같은 cron 표현식에서 날짜 및 요일 필드를 지정할 수 없다고 되어 있기 때문이다. 적어도 둘 중 하나에 값 또는 *(별)을 지정하는 경우 다른 필드에는?(물음표)를 지정해야 한다.

 

처음엔 이해가 잘 되지 않았는데 생각해 보면 쉬운 문제이다. 날짜가 *(별)이라면 모든 날짜를 의미하는데 요일도 *(별)이라면 모든 요일을 의미하는 것이기 때문이다. 올해 기준으로 예를 들면 2024년 2월 18일은 일요일이다. *(별)은 모든 요일을 포함하는데 2월 18일은 토요일이 될 수도 없고 월요일이 될 수도 없다. 오직 일요일일 수밖에 없다. 그렇기에 *(별)이 아닌 어떤 요일도 상관없다는?(물음표)가 되어야 한다. 역도 마찬가지다.

 

마지막으로 연도는 *(별)이므로 모든 연도를 의미한다. 최종적으로 매일 오전 10시(UTC+0)에 실행되는 규칙이다.

 

다시 원래의 목표로 돌아가 월요일부터 금요일 주중 오전 8시를 cron 표현식대로 작성해보자.

 

첫 번째 시도

 

cron(0 23 * * MON-FRI *)

 

오전 8시라고 해놓고 시간이 23인 이유는 시간이 UTC 기준이므로 한국 시간으로 설정하기 위해서는 한국 시간에서 9시간 앞선 시간으로 지정해야 한다. 9시간 시차까지 고려했겠다 자신만만하게 deploy 했으나 build 자체가 실패했다. 갑자기 배포, 빌드 이야기가 나오는 이유는 AWS SAM을 이용하여 규칙을 생성했기 때문이다.

 

고로 Unix/Linux의 cron 표현식과는 차이점이 있을 수 있다. 위 예시와 다른 점은 요일이?(물음표)가 아닌 특정 요일이라는 것이다. 이때 날짜를 의미하는 세 번째 자리에는 *(별)이 아닌?(물음표)가 와야 한다. 1일부터 31일까지는 토요일, 일요일도 포함되기 때문이다. 고로 어떤 날짜가 와도 상관없다는 의미인?(물음표)가 적합하다.

 

두 번째 시도

 

cron(0 23 ? * MON-FRI *)

 

build는 잘 되었고 규칙도 정상적으로 생성이 되었다. AWS console에 들어가서 이벤트 일정을 확인해보는데 예상하지도 못한 문제가 발생했다. 요일이 월~금이 아닌 화~토로 지정되어 있었다. 오전 8시로 시간은 UTC+9를 잘 고려했으나 요일이 밀리는 것은 생각하지 못했다. MON-FRI는 한국 기준이 아닌 UTC+0 기준 요일이기 때문이다. 우리가 원하는 대로 주중인 월~금을 지정하려면 SUN-THU(일~목)으로 바꿔야 한다.

 

세 번째 시도

 

cron(0 23 ? * 1-5 *)

 

요일을 문자로 표현하는 것이 읽는 사람으로 하여금 가독성이 좋다고 판단하여 사용했으나 SUN-THU는 오히려 혼란을 줄 수도 있다고 생각했다. 요일은 문자뿐만 아니라 숫자로도 표현할 수 있다. 1은 일요일, 2는 월요일 차례대로 7은 토요일을 의미한다. 차라리 숫자 1-5와 같이 표현하는 것이 AWS cron 표현식 규칙을 찾아보고 올바르게 이해할 수 있는 코드라고 생각하여 최종적으로 이렇게 작성하였다.

댓글