Airflow(2.0)采坑很多, 给出最经典的场景代码,然后给出解释
场景
时区是北京时间,今天是2021-01-14,我希望从今天开始(含今天),每周一到周五,下午3点,执行当天任务
包括的场景要素如下:
- 时区(timezone)设置
- 任务开始时间(start_date)的设置
- 任务周期(scedule_interval)设置
- 任务真正执行时间的设置(execution_date)
- 执行当天任务(任务中execution_date的使用)
# airflow config
[core]
default_timezone = Asia/Shanghai
[webserver]
default_ui_timezone = Asia/Shanghai
# DAG arguments
dag = DAG(
dag_id = 'demo_dag'
start_date = datetime(2021, 1, 13)
schedule_interval = '0 15 * * 1-5')
# Task
def demo_func(*args, **context):
execution_date = context['next_ds'] # !!!!!非常关键
print('Do current day job: %s' % execution_date)
demo_task = PythonOperator(
task_id='demo_task',
python_callable=demo_func,
op_args=['foo'],
dag=demo_dag,
)
背后逻辑
时区设置
配置文件设置之后,Dag会取用,所以不需要在dag的start_date里面另外设置tzinfo
任务开始时间的设置
期待2021-01-14
开始跑,那么dag的start_date
需要设置前一天2021-01-13
因为真实的第一次运行时间是start_date + schedule_interval
所以如果start_date
设置的是2021-01-14
,那么真实的第一次运行时间是2021-01-15 15:00:00
周期的设置
可以放心使用crontab
语法,例如场景中的0 15 * * 1-5
关于execution_date
,尤其是执行当日任务
对于通常的ETL任务来说,都是后一天跑前一天的数据,所以Airflow的逻辑就是这样:
- 计算一个下一次的
excution_date
,存入dag的next_dagrun
字段 - 计算一个下一次dagrun的触发时间,存入dag的
next_dagrun_create_after
字段 - scheduler不停检查当前时间和
next_dagrun_create_after
字段,当前时间超过next_dagrun_create_after
视为需要执行 - 如果发现有需要创建的dagrun,则以
next_dagrun
为execution_date
创建一个Dagrun实例去执行
所以,恶心的事情就来了2021-01-14 15:00:00
执行的dagrun, execution_date
是2021-01-13
!
当在我的场景之中,我其实是想收盘后下载当天的数据,所以期待的就是
execution_date
= DagRun的真实执行日期
翻看源码之后,发现Airflow贯彻的是ETL的逻辑
execution_date
= DagRun的真实执行时间
- 一个schedule_interval周期
所以,要想满足场景,只能是日期依赖的代码不使用macro
的exection_date | ds
,而是使用next_exection_date | next_ds