
이 게시물은
airflow 2.10.5버전을 사용해서 작성됐습니다.
3.x버전과 조금 다를 수 있으니 유의하시기 바랍니다.
Airflow 에서 DAG 를 작성할 때 가장 중요한 파라미터 schedule 이라고 생각합니다.

그런데 schedule 을 제대로 사용하려면 cron 표현식부터 시작해서
catchup 그리고 이와 엮여서 동작하는 data interval 대한 이해가 필요합니다.
이를 위해서 지금부터 다음과 같은 것들을 순서대로 알아보도록 하겠습니다.
cron 표현식 이란 unix 계열의 OS 에서 사용하던 crontab(cron table) 이라는
설정 파일에서 사용되는 표현식입니다.
표현식의 목적은 주기적으로 실행할 shell 명령어를 스케줄링하는데 사용됐죠.
오늘날 cron 표현식 은 crontab 뿐만 아니라
다양한 스케줄링 소프트웨어에서도 흔히 사용하고 있습니다.
Airflow 도 그중 하나고요 😊
cron 표현식은 일단 5 개 문자로 표현됩니다.
위 그림에서 * 들이 보이죠? 저 문자 하나하나가 어떤 특정 시간의 단위들을 의미합니다.
맨 왼쪽부터 분, 시간, 일자, 월, 요일/주 입니다.
각각의 단위에는 다음과 같은 값들이 들어갈 수 있습니다.
분: 0 ~ 59시간: 0 ~ 23일자: 0 ~ 31월: 1 ~ 12요일/주:
0(=일요일)~6(=토요일)- 요일에 더해서
주까지 표현하려면#을 사용합니다.- 예를 들어서 첫째주 일요일을 표현하려면
0#1처럼 표현합니다.주를 작성하지 않으면 매주로 인식합니다.
이렇게 딱딱한 값들을 넣는 것 외에도 다양한 표현을 사용할 수 있습니다.
* : 0 0 * * * : 매월/매주/매일 정각을 의미합니다.L : 일자 와 요일/주 에서만 사용할 수 있습니다.0 0 L * * : 매월 마지막 일자의 정각0 0 * * 6#L : 매월 마지막 주 토요일 정각- :0 0-6 * * * : 00시부터 06시까지 매시간 실행, :0 0,12 * * * : 매일 00시와 12시에 실행 / :?? 마다 할 것이다 를 표현한 겁니다.*/20 * * * * : 매 20분마다 실행10/20 * * * * : 매 20분마다 실행되지만, 시작이 10분에서 시작*/? 처럼 사용할 때 * 의 의미는 단위별 가장 낮은 값을 의미합니다.alias 입니다. (아래 그림참고)
schedule="@daily" 처럼 인자값을 줘서 사용합니다.cron 표현식은 이정도만 알아두죠! 다음으로 넘어 갑시다.
catchup 은 현재까지 실행하지 못한 ...
스케줄된 작업 들을 실행할지 (catchup=True)스케줄된 작업 만 실행할지 (catchup=False)... 를 결정하는 파라미터입니다.
그런데 여기서 말하는 스케줄된 작업 이라는 게 정확히 뭘 의미할까요?
그건 바로
data interval입니다
airflow 3.x를 사용하시면 이 목차의 내용은 skip 하셔도 됩니다 😊
그냥airflow 2.x에는 이렇게 동작했구나~ 하고 느낌만 알고 넘어가셔도 좋습니다.
Airflow 에서 data interval 은 DAG 실행이 다루는 시간 범위를 나타냅니다.
그런데 사실 data interval 은 이러한 정의보다는 다른 이유 때문에 중요합니다.
data interval 중요한 이유는 DAG run,
즉 DAG 의 실행 그 자체 와 1:1 로 매칭되는 개념이기 때문입니다.
DAG 가 실행된 거면 그것은 하나의 dag interval 이 존재했기에 가능한 겁니다.
이를 더 깊게 이해하기 위해서 아래와 같은 예시 DAG 를 작성해보겠습니다.
from airflow import DAG
from airflow.operators.empty import EmptyOperator
import pendulum
# 예시 DAG 작성
with DAG(
dag_id="dags_for_blogging",
# 매일 오전 6시에 동작
schedule="0 6 * * *",
# 스케줄의 시작 시간은 2025-06-04 부터이고,
# 현재 시각은 2025-06-06 13:00:00 입니다.
start_date=pendulum.datetime(2025, 6, 4, tz="Asia/Seoul"),
catchup=True,
) as dags:
# 아무런 동작을 하지 않는 EmptyOperator 작성
task_1 = EmptyOperator( task_id="task_1" )
task_1
[
start_date:2025-06-04/ 현재시각:2025-06-06 13:30] 이라는 점을 기억해주세요!
자, 이렇게 세팅하고 DAG 를 airflow 에 올려보겠습니다.
airflow ui 에서 dag 를 검색해서 찾아보면 위 그림처럼 Pause 상태입니다.
해당 토글 버튼을 클릭해서 UnPause 하겠습니다.
그랬더니 위처럼 자동으로 실행됩니다. catchup=True 를 해서 여태까지 못했던
작업들도 한번에 한 것을 확인할 수 있습니다.
이번에는 각각의 DAG run 의 Detail 정보를 조회해보겠습니다.
첫번째 DAG RUN

두번째 DAG RUN

각각의 DAG Run 의 Data interval start, Data interval end 를 집중해서 보세요.
이 2개의 값에 의해서 하나의 data interval 이 정의되는 겁니다!
현재는 data interval 이 다음과 같이 존재합니다.
data interval [2025-06-04 06:00:00 ~ 2025-06-05 06:00:00]
data interval [2025-06-05 06:00:00 ~ 2025-06-06 06:00:00]
이렇게 2개의 interval 이 생성됐기 때문에 2번의 DAG run 도 가능했다는 겁니다.
Dag run == data interval 이라는 것을 눈으로 확인해봤습니다.
보충: 만약
catchup=False였다면 어땠을까요?
그때는 2개의 interval 중에서마지막 data interval인
data interval [2025-06-05 06:00:00 ~ 2025-06-06 06:00:00]에 의해서
한번의DAG run이 발생합니다.
data interval이 2개만 만들어지는 이유는start_date=2025.06.04로 설정해서 그런겁니다.
이와 관련해서는 바로 다음 목차인주의할 점들에서 더 자세히 다룹니다.
data interval 에 의해서 실행되는 시점은 Data interval end 입니다.
Data interval start 가 아닙니다! start 라는 문구 때문에 오해하기 쉽습니다.
그렇다면 Data interval start 은 뭘까요? 바로 이전의 Dag run 시점 입니다.
다음으로 주의할 점은 start_date 에 의한 data interval 의 생성 범위입니다.
data interval 을 생성하기 위해서는 data interval start, data interval end 가
한쌍을 이뤄야 합니다. 이런 이유로 start_date 가 data interval start 보다
미래냐, 과거냐에 따라서 data interval 이 생성되기도, 안 하기도 합니다.
쉬운 이해를 위해서 이전에 사용했던 예시 코드에 의해서 생성된 data interval 들과,
start_date 의 관계성을 그림으로 그려봤습니다.

위 그림을 보면 알겠지만
start_date와data interval start에 의해서 DAG 의 첫data interval의 범위가 결정됩니다. 이점을 꼭 기억하시기 바랍니다.
그렇다면 start_date 를 2025.06.06, 즉 오늘과 동일하게 바꾸면 어떻게 될까요?
먼저 그림을 통해서 봅시다.

보면 알겠지만 이럴 때는 data interval 생성 자체가 안됩니다.
실제로도 이런 상태의 DAG 를 Airflow ui 에서 Unpause 를 해도
아무런 일이 발생하지 않습니다. (아래 그림 참고)
대신 억지로라도 마지막 data interval 을 생성하고 싶다면 ui 화면에서
Dag Trigger 버튼을 클릭하면 됩니다. (아래 그림 빨간박스 친 버튼)

그러면 위 그림처럼 Dag Run 이 발생합니다.
이렇게 Dag Trigger 로 강제 실행하면 Trigger 시점에서 가장 가까운 과거의
data interval end 시점을 갖는 data interval 이 생성되고 Dag 가 실행됩니다.
3. 주의할 점들 목차를 읽다보니... 뭔가 어렵고 헷갈립니다.
end 가 trigger 시점이고, 한번의 실행을 위해서 start_date 와
data interval 등을 을 머릿속으로 연산하고... 머리가 아픕니다!
이런 이유로
airflow 3.x에서는 한가지 큰 변화가 생겼습니다.
기존 airflow 2.x 까지는 data interval 이 Dag run 을 발생시키는 알고리즘 을 사용했습니다.
하지만
airflow 3.x부터는default로data interval의 생성여부를 따지지 않고
trigger 시점(=기존data interval end)이 되기만하면Dag run을 발생하는 알고리즘을 사용합니다. (관련 문서 링크)
이러면 data interval end, data interval start 를 구분하는게 큰 의미가 없어지죠?
그래서 airflow 3.x 에서는 data interval start 가 data interval end 의 값과 동일하게 세팅됩니다. (더 자세한 동작 방식의 차이는 이 링크를 참조)
물론 airflow 3.x 에서도 여전히 이전처첨 airflow 2.x 의 data interval 방식의 DAG run 알고리즘을 사용할 수 있으며, DAG 별로 선택적으로 하거나 global 하게 설정할 수도 있습니다.
이상으로 글을 마치겠습니다.
읽어주셔서 감사합니다!