Airflow 不遵循调度配置执行

在 Airflow 的使用过程中,曾多次遇到令人惊奇的现象,其中之一便是它没有按照 dag 中的配置执行。

可能你也会遇到这样的情况,为什么配置了 schedule_intervalstart_date,但是依旧没有按照调度配置的时间自动执行。

举个栗子

比如我这么配:

1
2
3
4
5
6
7
8
9
10
11
12
from datetime import datetime, timedelta, timedelta

default_args = {
'owner': 'amos',
'depends_on_past': False,
'start_date': datetime.now(),
}

dag = DAG('test_rerun_dag',
default_args=default_args,
description='test_rerun_dag',
schedule_interval="*/1 * * * *")

照理说它应该按照配置中写的,每分钟执行一次操作。可是它没有,是它变心了吗?

不,不是的。

这究竟是为什么

Airflow sets execution_date based on the left bound of the schedule period it is covering, not based on when it fires (which would be the right bound of the period) .

原因在于 Airflow 是个有原则的程序,它有个窗口的概念,会把 start_date 开始后,符合 schedule_interval 定义的第一个时间点记为 execution_date,但是会在下个时间点到达时才开始运行。也就是说由于这个窗口的原因,last run 会滞后一个周期。

所以,按上面的配置来说,每次当 scheduler 读到了这段 DAG,它会拿小本本记下 start_date 和每分钟执行的操作,准备在下一分钟开始执行了。但是当下一分钟来临的时候,它看了看表,嗯!start_date + 1,那么 execution_date 也 + 1,于是把小本本上的 start_date 划掉重写。所以 start_date 在不断被覆盖的过程中,任务没有像我们预想中的在调度奔跑,反而一直是挂起状态。

这可咋整啊

那么如何才能真正地让它规律地执行呢?

将 start_date 往前错位到上一个周期

什么意思呢?假如本例中的每分钟执行一次,那就将 start_date 调整到上一分钟的状态

‘start_date’: datetime.now()

‘start_date’: datetime.now() - timedelta(minutes=1)

这下 scheduler 就可以在小本本工工整整地记录每一次调度计划,而不用写了划,划了写,把小本本涂得黑黑的了!


如果你的 dag 趁你不注意卡在running 状态下不能动弹,或许你可以改改调度时间或周期。

或者试试参考这篇文章:Airflow 居然趁服务器不注意卡在 running 状态不执行