Airflow: Time Zone
Airflow Time Zones
Time Zones — Airflow Documentation
airflow.apache.org
Pendulum
Documentation | Pendulum - Python datetimes made easy
Installation Installing pendulum is quite simple: or, if you are using poetry: Introduction Pendulum is a Python package to ease datetimes manipulation. It provides classes that are drop-in replacements for the native ones (they inherit from them). Special
pendulum.eustace.io
- Web UI
- 개념
- datetime 객체의 naive와 aware
- navie한 datetime 객체 해석
- 멀티 노드
- DAG에서 시간대
- 템플릿
- Cron schedule
- Timedelta
Time Zone
Airflow는 기본적으로 시간대(time zone)를 사용합니다. 내부적으로 datetime 정보를 UTC로 보관하고, 데이터베이스에도 UTC로 저장합니다. 따라서 시간대에 따른 schedule로 DAG를 실행할 수 있습니다. Airflow 사용자의 로컬 시간대는 신경쓰지 않으므로 UTC가 아닌 다른 시간대로 표시하고 싶다면 직접 변경해야 합니다.
시간대를 생각할 때 주요한 요소는 서머 타임(ST) 또는 일광 절약 시간제(DST)입니다. 이는 여름에 시계 시간을 1시간 더하는 것으로, 예를 들면 UTC+1 국가는 UTC+2가 되는 것입니다. 햇빛을 효율적으로 사용하자는 의도를 가진 제도로, 한국에서는 현재 시행하지 않지만 미국이나 유럽 등 여러 국가에서 시행하고 있습니다. DST는 컴퓨터로 실제 시간을 다룰 때 의도치 않은 작동을 일으키는 원인이므로 신경써야 합니다. Airflow가 시간을 다룰 때 UTC를 쓰는 주된 이유이기도 합니다.
Airflow가 표시하는 시간대는 airflow.cfg의 [core]의 default_timezone에서 변경할 수 있습니다. 기본 값은 UTC이고, system을 입력하여 로컬 시스템의 설정을 따르게 하거나 IANA 시간대(Asia/Seoul 형식)를 입력할 수 있습니다. 이는 파이썬의 pendulum 라이브러리를 통해 구현됩니다.
Web UI
Web UI에서 시간은 기본적으로 UTC로 표시됩니다. 우상단 시간 표시를 클릭하여 다른 시간대로 변경할 수 있습니다.
브라우저의 시간대를 감지하여 "Local"로 표시하고, airflow.cfg의 [core]의 default_timezone은 "Server"로 표시합니다. 여기서 선택한 시간대는 LocalStorage에 저장되므로 브라우저별로 적용됩니다.
airflow.cfg의 [webserver]의 default_ui_timezone을 빈 값으로 두거나 시간대를 기재하면, UI는 시간을 해당 시간대로 표시합니다. 기본 값은 시간을 일관적으로 표시하기 위해 UTC로 설정되어 있습니다.
개념
datetime 객체의 naive와 aware
파이썬의 datetime.datetime 객체는 tzinfo라는 datetime.tzinfo 인스턴스를 속성으로 갖는데, 이로서 시간대 정보를 저장할 수 있습니다. 이 속성이 설정되어 있고 offset(UTC와의 차이)을 규정할 때 datetime 객체는 aware하다고 하고, 아닌 경우 naive하다고 합니다.
from airflow.utils import timezone
# UTC로 현재 시간(datetime.datetime의 utcnow()와 다르게 aware)
now = timezone.utcnow()
# datetime.datetime 객체 생성
# tzinfo 미입력시 default_timezone을 시간대로 사용
a_date = timezone.datetime(2023, 1, 1)
# 해당 시간이 aware인지
timezone.is_localized(a_date) # True
# 해당 시간이 naive인지
timezone.is_naive(a_date) # False
Airflow에 사용하는 datetime 객체는 aware여야 합니다.
naive한 datetime 객체 해석
Airflow는 aware한 datetime 객체만 다루지만, DAG 정의의 start_date/end_date는 naive한 datetime 객체를 허용합니다. 이는 대부분 이전 버전 호환성을 위함입니다. start_date/end_date에 naive한 datetime이 오면 Airflow의 기본 시간대를 적용합니다. 이때 해당 datetime 값이 이미 기본 시간대에 맞추어져 있다고 간주합니다. 즉 값을 바꾸진 않습니다. 다만 이런 방식은 DST에 따른 시간 변경이 있으면 오류가 발생할 수 있으므로 항상 aware한 datetime 객체만 제공하는 게 좋습니다.
멀티 노드
DAG는 여러 worker에서 실행될 수 있으므로, 모든 Airflow 노드에서 같은 기본 시간대를 사용해야 합니다.
DAG에서 시간대
DAG를 만들 때 시간대에 신경써야 할 부분은 start_date를 pendulum을 통해 정하는 것뿐입니다. datetime 라이브러리는 여러 한계가 있으므로 DAG에서 허용하지 않습니다.
import pendulum
dag = DAG("my_tz_dag", start_date=pendulum.datetime(2023, 1, 1, tz="Asia/Seoul"))
op = EmptyOperator(task_id="empty", dag=dag)
print(dag.timezone) # <Timezone [Asia/Seoul]>
task에도 따로 start_date/end_date를 설정할 수 있지만, 항상 DAG에 사용한 시간대에 따라 data interval이 정해진다는 것을 유의해야 합니다.
템플릿
Airflow는 템플릿을 사용할 때 aware한 datetime 객체를 반환합니다. 하지만 로컬 시간대로 변환하지 않고 UTC로 놔두기 때문에, 필요한 경우 스스로 변환해야 합니다.
import pendulum
logical_date = "{{ ds }}"
# 시간대 생성
local_tz = pendulum.timezone("Asia/Seoul")
# 해당 시간대로 변경
local_tz.convert(logical_date)
Cron schedule
cron schedule을 사용하는 DAG는 자동적으로 DST를 고려합니다. 예를 들어, US/Eastern 시간대를 사용하며 schedule이 0 0 * * *인 DAG는 평소에 05:00에 실행되다가 DST에는 04:00에 실행됩니다.
Timedelta
timedelta 또는 relativedelta로 schedule한 DAG는 start date에 한해 자동적으로 DST를 고려하지만 이어지는 후속 실행에서는 적용하지 않습니다. 예를 들어, US/Eastern 시간대를 사용하며 start_date가 pendulum.datetime(2023, 1, 1, tz="UTC")이며 schedule이 timedelta(days=1)인 DAG는 start date가 DST 기간이 아니므로 05:00에 실행되고, 하루 간격으로 실행되는 다음 실행부터는 DST 기간이 오더라도 항상 05:00에 실행됩니다.