在我的DAG中,我有一些任务只能在星期六执行。因此,我使用BranchPythonOperator在星期六的任务和DummyTask之间进行分支。之后,我加入了两个分支,并希望执行其他任务。
工作流程如下:
Gravity Forms
在这里,我将dummy3的触发规则设置为'one_success'
,一切正常。
我遇到的问题是BranchPythonOperator上游的某些操作失败时:
BranchPythonOperator和分支正确地具有状态'upstream_failed'
,但是加入分支的任务变为'skipped'
,因此整个工作流程显示为'success'
。
我尝试使用'all_success'
作为触发规则,但是如果某些失败使整个工作流程失败,但如果没有失败,则可以跳过dummy3。
我也尝试使用'all_done'
作为触发规则,然后即使没有失败,它也可以正常工作,但是如果失败,仍然可以执行dummy3。
我的测试代码如下:
from datetime import datetime, date
from airflow import DAG
from airflow.operators.python_operator import BranchPythonOperator, PythonOperator
from airflow.operators.dummy_operator import DummyOperator
dag = DAG('test_branches',
description='Test branches',
catchup=False,
schedule_interval='0 0 * * *',
start_date=datetime(2018, 8, 1))
def python1():
raise Exception('Test failure')
# print 'Test success'
dummy1 = PythonOperator(
task_id='python1',
python_callable=python1,
dag=dag
)
dummy2 = DummyOperator(
task_id='dummy2',
dag=dag
)
dummy3 = DummyOperator(
task_id='dummy3',
dag=dag,
trigger_rule='one_success'
)
def is_saturday():
if date.today().weekday() == 6:
return 'dummy2'
else:
return 'today_is_not_saturday'
branch_on_saturday = BranchPythonOperator(
task_id='branch_on_saturday',
python_callable=is_saturday,
dag=dag)
not_saturday = DummyOperator(
task_id='today_is_not_saturday',
dag=dag
)
dummy1 >> branch_on_saturday >> dummy2 >> dummy3
branch_on_saturday >> not_saturday >> dummy3
我只是想出一个丑陋的解决方法:
dummy4代表我实际需要运行的任务,dummy5只是一个假人。
dummy3仍然具有触发规则'one_success'
。
现在,如果没有上游故障,则哑元3和哑元4将运行,如果星期二不是星期六,哑元5将“运行”,如果星期六是星期六,则将被跳过,这意味着DAG在这两种情况下都标记为成功。
如果上游发生故障,则将dummy3和dummy4跳过,并将dummy5标记为'upstream_failed'
,并将DAG标记为失败。
此变通办法可以使我的DAG正常运行,但是我仍然希望没有任何变通办法的解决方案。
答案 0 :(得分:4)
您可以使用的一种解决方法是,将DAG的第二部分放在SubDAG中,就像我在说明您的示例的以下代码中所做的那样:https://gist.github.com/cosenal/cbd38b13450b652291e655138baa1aba
它可以按预期工作,并且可以说比您的解决方法更干净,因为您没有任何其他辅助虚拟运算符。但是,您失去了扁平结构,现在必须放大SubDag才能查看内部结构的详细信息。
更一般的观察:在对您的DAG进行试验之后,我得出的结论是Airflow需要类似JoinOperator之类的东西来替换您的Dummy3运算符。让我解释。您描述的行为来自以下事实:DAG的成功仅取决于最后一个运算符是否成功(或被跳过!)。
以下以“成功”状态结尾的DAG是支持上述声明的MWE。
def python1():
raise Exception('Test failure')
dummy1 = PythonOperator(
task_id='python1',
python_callable=python1,
dag=dag
)
dummy2 = DummyOperator(
task_id='dummy2',
dag=dag,
trigger_rule='one_success'
)
dummy1 >> dummy2
有一个JoinOperator仅在其中一个立即父母成功并且其他所有父母都被跳过时才触发,这很酷,而不必使用trigger_rule
参数。
或者,可以解决触发问题的all (success | skipped)
可以解决您遇到的问题,您可以将其应用于Dummy3。不幸的是,我认为您还不能在气流上创建自定义触发规则。
编辑:在该答案的第一版中,我声称触发规则one_success
和all_success
根据 all 的成功程度触发DAG中运营商的祖先,而不仅仅是直系父母。这与documentation不符,实际上,以下实验对其无效:https://gist.github.com/cosenal/b607825539aa0d308f10f3095e084fac
答案 1 :(得分:2)
在任何情况下,将dummy3的触发规则设置为'none_failed'
都会使其以预期状态结束。
请参见https://airflow.apache.org/concepts.html#trigger-rules
EDIT :当问及回答此问题时,似乎'none_failed'
触发规则尚不存在:它是在2018年11月添加的