Airflow의 다양한 스케줄링 방식 총정리!

NewNewDaddy·2026년 2월 2일

AIRFLOW

목록 보기
6/6
post-thumbnail

0. INTRO

왜 Airflow 스케줄링을 이해해야 할까?

데이터 파이프라인을 운영하다 보면 "매일 새벽에 ETL을 돌리고 싶다", "평일 오후에만 리포트를 생성하고 싶다", "3일마다 한 번씩 배치를 돌리고 싶다" 같은 요구가 생깁니다. Apache Airflow에서는 DAG의 schedule 파라미터로 이런 실행 주기를 정의합니다. 스케줄 방식을 잘못 설정하면 과거 구간이 한꺼번에 돌아가는 catchup 문제가 생기거나, 의도와 다른 시간에 DAG가 실행될 수 있어요. 이 글에서는 Airflow가 제공하는 4가지 스케줄링 방식(Presets, Cron, Timedelta/Delta, Timetable)을 개념부터 코드 예시, 실무 선택 기준까지 정리합니다.

Airflow 스케줄링 방식 개요

Airflow에서 DAG 실행 시점을 정하는 방식은 크게 네 가지로 나눌 수 있습니다.

  1. Presets (사전 정의 문자열)@daily, @hourly 등 고정된 의미의 문자열
  2. Cron Expression — Unix cron 형식의 5필드 표현식
  3. Timedelta / DeltaDataIntervalTimetable — 고정 간격(예: 3일마다, 6시간마다)
  4. Timetable (Custom / EventsTimetable) — 불규칙한 날짜·이벤트 기반 스케줄

1. Presets (사전 정의 문자열)

1) 개요

주요 기능:

  • Airflow가 미리 정의한 문자열로, "매일 자정", "매시간", "매주 일요일" 등 흔한 주기를 한 번에 표현
  • 내부적으로 cron 표현식으로 변환되어 처리됨
  • 코드가 짧고 의도가 바로 읽혀서 초보자에게 적합

실무 관점:

  • 일일 리포트, 시간 단위 로그 수집, 주간/월간 정산처럼 규칙적인 주기가 있을 때 가장 먼저 고려
  • "매일 새벽 0시에 돌리면 된다" 수준이면 @daily 한 줄로 해결
  • 나중에 "매일 오전 9시로 바꿔 달라"는 요구가 생기면 cron 표현식(0 9 * * *)으로 전환하는 경우가 많음

언제 필요한가?

  • 단순하고 일반적인 주기만 필요할 때
  • 팀 내에서 "매일/매시간/매주"라는 표현으로 소통할 때
Preset의미
@daily매일 자정 (0 0 * * *)
@hourly매 시간 정각 (0 * * * *)
@weekly매주 일요일 자정 (0 0 * * 0)
@monthly매월 1일 자정 (0 0 1 * *)
@yearly매년 1월 1일 자정
@once한 번만 실행
None스케줄 없음 (수동 트리거)
from airflow import DAG
from airflow.operators.empty import EmptyOperator
from pendulum import datetime

with DAG(
    dag_id="preset_example",
    schedule="@daily",  # 매일 자정 실행
    start_date=datetime(2026, 1, 1, tz="Asia/Seoul"),
    catchup=False,
):
    task = EmptyOperator(task_id="daily_task")

2. Cron Expression

1) 개요

주요 기능:

  • Unix cron과 동일한 5필드 형식(분, 시, 일, 월, 요일)으로 실행 시점을 세밀하게 지정
  • "평일 오후 4시", "매월 1일·15일 자정", "30분마다" 등 복합 조건 표현 가능
  • Airflow 내부에서는 CronDataIntervalTimetable로 변환되어 동작

실무 관점:

  • 업무 시간대에만 돌리거나(예: 평일 9–18시), 특정 요일·특정 일자에만 실행해야 할 때 cron이 표준 선택
  • 예: 0 16 * * MON-FRI → 평일 오후 4시, 0 0 1,15 * * → 매월 1일·15일 자정
  • 타임존은 DAG의 start_date 등에서 사용하는 datetime에 tz를 지정해 일관되게 맞추는 것이 중요

언제 필요한가?

  • "특정 요일", "특정 시각", "특정 일자" 조합이 필요할 때
  • Preset으로는 표현이 안 되는 구체적인 시간 조건이 있을 때
┌─────── 분 (0-59)
│ ┌───── 시 (0-23)
│ │ ┌─── 일 (1-31)
│ │ │ ┌─ 월 (1-12)
│ │ │ │ ┌ 요일 (0-6, 0=일요일)
│ │ │ │ │
* * * * *
from airflow import DAG
from airflow.operators.empty import EmptyOperator
from pendulum import datetime

with DAG(
    dag_id="cron_example",
    schedule="0 16 * * MON-FRI",  # 평일 오후 4시
    start_date=datetime(2026, 1, 1, tz="Asia/Seoul"),
    catchup=False,
):
    task = EmptyOperator(task_id="weekday_afternoon_task")

자주 쓰는 패턴:

  • 0 9 * * * → 매일 오전 9시
  • */30 * * * * → 30분마다
  • 0 0 1,15 * * → 매월 1일, 15일 자정

3. Timedelta / DeltaDataIntervalTimetable

1) timedelta 직접 사용 (간단한 방식)

주요 기능:

  • "N일마다", "N시간마다", "N분마다"처럼 고정 간격 실행을 표현
  • schedule=timedelta(days=3)처럼 넣으면 Airflow가 내부적으로 DeltaDataIntervalTimetable로 변환

실무 관점:

  • "3일마다 한 번", "6시간마다 한 번" 같은 주기는 cron보다 timedelta가 의도가 분명함
  • 예: timedelta(days=3), timedelta(hours=6), timedelta(minutes=30)
  • cron은 "언제"를 지정하고, timedelta는 "간격"을 지정한다는 차이를 두고 선택하면 됨

언제 필요한가?

  • 실행 시점이 "매일 0시"가 아니라 "N시간/ N일 간격"일 때
  • 주기만 중요하고 정각 맞춤이 필요 없을 때
from airflow import DAG
from airflow.operators.empty import EmptyOperator
from pendulum import datetime
from datetime import timedelta

with DAG(
    dag_id="timedelta_simple_example",
    schedule=timedelta(days=3),  # 3일마다 실행
    start_date=datetime(2026, 1, 1, tz="Asia/Seoul"),
    catchup=False,
):
    task = EmptyOperator(task_id="every_3_days_task")

2) DeltaDataIntervalTimetable 사용 (명시적 방식)

주요 기능:

  • Timetable 객체를 직접 지정해 "고정 간격" 스케줄을 명시적으로 표현
  • 커스텀 Timetable과 조합하거나, 코드에서 "Timetable 기반 스케줄"임을 드러내고 싶을 때 사용

실무 관점:

  • schedule=timedelta(...)와 동작은 동일함. 다만 "Timetable을 쓰고 있다"는 것이 코드에 드러남
  • 커스텀 Timetable을 만들거나, 여러 Timetable을 조합하는 고급 패턴으로 넘어갈 때 같은 계열로 이해하면 됨

언제 필요한가?

  • 고정 간격을 Timetable API 수준에서 명시하고 싶을 때
  • 커스텀 Timetable과의 일관성을 위해 같은 방식으로 쓰고 싶을 때
from airflow import DAG
from airflow.operators.empty import EmptyOperator
from airflow.timetables.simple import DeltaDataIntervalTimetable
from pendulum import datetime
from datetime import timedelta

every_3_days = DeltaDataIntervalTimetable(timedelta(days=3))

with DAG(
    dag_id="delta_timetable_example",
    schedule=every_3_days,
    start_date=datetime(2026, 1, 1, tz="Asia/Seoul"),
    catchup=False,
):
    task = EmptyOperator(task_id="every_3_days_task")
구분timedelta 직접 사용DeltaDataIntervalTimetable
코드간결함명시적
내부 동작자동으로 Timetable로 변환됨직접 Timetable 사용
사용 시점단순한 경우커스텀 Timetable과 조합 시

💡 schedule=timedelta(...)를 넣으면 Airflow 내부에서 DeltaDataIntervalTimetable로 자동 변환됩니다. 결과는 동일합니다.


4. Timetable (Custom / EventsTimetable)

1) EventsTimetable

주요 기능:

  • 특정 datetime 목록만큼만 DAG를 실행하도록 함
  • 공휴일, 이벤트일, 월말 등 불규칙한 날짜에만 돌리고 싶을 때 사용
  • Airflow 2.2+에서 도입된 Timetable API의 대표 활용 예

실무 관점:

  • "이 날짜들에만 실행"이 필요할 때(예: 월별 마감일, 특별 이벤트 일자)
  • event_dates 리스트를 코드나 설정에서 생성해 넘기면 됨
  • catchup=True와 조합하면 지정한 과거 날짜들도 한 번씩 실행 가능

언제 필요한가?

  • 실행 일자가 규칙적인 주기가 아닐 때
  • 공휴일 제외, 특정 영업일만 등 불규칙한 날짜 집합이 필요할 때
from airflow.sdk import dag, task
from pendulum import datetime
from airflow.timetables.events import EventsTimetable

special_dates = EventsTimetable(
    event_dates=[
        datetime(2026, 1, 1, tz="Asia/Seoul"),
        datetime(2026, 1, 15, tz="Asia/Seoul"),
        datetime(2026, 1, 26, tz="Asia/Seoul"),
        datetime(2026, 1, 30, tz="Asia/Seoul"),
    ]
)

@dag(
    schedule=special_dates,
    start_date=datetime(2026, 1, 1, tz="Asia/Seoul"),
    end_date=datetime(2026, 1, 31, tz="Asia/Seoul"),
    catchup=True,
)
def events_timetable_example():
    @task
    def run_on_special_date():
        print("특별한 날에만 실행!")

    run_on_special_date()

events_timetable_example()

5. 스케줄링 방식 요약

방식사용 시점예시
Presets단순하고 일반적인 주기@daily, @hourly
Cron특정 시간/요일/일자 지정 필요0 16 * * MON-FRI
Timedelta고정 간격 실행timedelta(days=3)
DeltaDataIntervalTimetable고정 간격 (명시적)Timetable 객체로 조합
EventsTimetable불규칙 날짜, 이벤트 기반공휴일, 이벤트 날짜 등

6. Timetable Import 정리

# Delta 관련
from datetime import timedelta
from airflow.timetables.simple import DeltaDataIntervalTimetable

# Events 관련
from airflow.timetables.events import EventsTimetable

# Cron 관련 (필요시)
from airflow.timetables.simple import CronDataIntervalTimetable

7. 실무 활용 가이드

신규 DAG 설계 시 선택 순서
1. "매일/매시간/매주" 수준이면 → Presets (@daily, @hourly 등)
2. "평일 오후 4시", "매월 1일·15일"처럼 구체 시각/요일/일자가 필요하면 → Cron
3. "N시간/ N일마다" 간격이 중요하면 → Timedelta (또는 필요 시 DeltaDataIntervalTimetable)
4. 날짜가 불규칙하면 → EventsTimetable 또는 커스텀 Timetable

주의사항

  • start_datecatchup: 과거 구간을 채울지 여부를 catchup로 제어. 기본값이 True이므로 의도치 않은 대량 실행을 막으려면 catchup=False를 자주 사용함
  • 타임존: pendulum.datetime(..., tz="Asia/Seoul") 등으로 DAG와 태스크에서 타임존을 통일할 것
  • Timetable은 Airflow 2.2+ 기능이며, schedule이 내부적으로 어떻게 Timetable로 매핑되는지 이해하면 디버깅과 확장에 유리함

8. 마무리

  • Airflow 스케줄은 Presets → Cron → Timedelta/Delta → EventsTimetable(커스텀) 순으로 "단순 규칙 → 세밀한 시간 → 간격 → 불규칙 일자"를 다룹니다.
  • 실무에서는 "매일 새벽"이면 Preset, "평일 특정 시각"이면 Cron, "N일마다"면 Timedelta, "이 날들만"이면 EventsTimetable로 정리하면 선택이 쉽습니다.
  • catchup과 타임존 설정을 함께 점검하면 예상치 못한 실행을 줄일 수 있습니다.

참고 자료:

profile
데이터 엔지니어의 작업공간 / #PYTHON #CLOUD #SPARK #AWS #GCP #NCLOUD

0개의 댓글