Airflow 气流:当短路跳过某些上游时,运行任务

Airflow 气流:当短路跳过某些上游时,运行任务,airflow,Airflow,我有一个任务,我将调用具有多个上游连接的final。当ShortCircuitOperator跳过其中一个上游时,此任务也会被跳过。我不想跳过final任务,因为它必须报告DAG成功 为了避免它被跳过,我使用了trigger\u rule='all\u done',但它仍然被跳过 如果我使用BranchPythonOperator而不是ShortCircuitOperatorfinal任务不会被跳过。分支工作流似乎是一个解决方案,尽管不是最优的,但现在final将不考虑上游任务的失败 如何使其仅

我有一个任务,我将调用具有多个上游连接的
final
。当
ShortCircuitOperator跳过其中一个上游时,此任务也会被跳过。我不想跳过
final
任务,因为它必须报告DAG成功

为了避免它被跳过,我使用了
trigger\u rule='all\u done'
,但它仍然被跳过

如果我使用
BranchPythonOperator
而不是
ShortCircuitOperator
final
任务不会被跳过。分支工作流似乎是一个解决方案,尽管不是最优的,但现在
final
将不考虑上游任务的失败

如何使其仅在上游成功或跳过时运行

示例短路DAG:

来自气流导入DAG
从airflow.operators.dummy_operator导入dummy operator
从afflow.operators.python_operator导入ShortCircuitOperator
从日期时间导入日期时间
从随机导入randint
默认参数={
“所有者”:“气流”,
“开始日期”:日期时间(2018年8月1日)
dag=dag(
“短路测试”,
默认参数=默认参数,
计划时间间隔=“****”,
catchup=错误)
def短路\u fn():
返回randint(0,1)=1
task_1=DummyOperator(dag=dag,task_id='task_1')
task_2=DummyOperator(dag=dag,task_id='task_2')
work=dummy运算符(dag=dag,task\u id='work')
short=shortcircuit操作符(dag=dag,task\u id='short\u circuit',python\u callable=shortcircuit\u fn)
final=dummy操作符(dag=dag,task\u id=“final”,trigger\u rule=“all\u done”)
任务1>>简短>>工作>>最终
任务1>>任务2>>最终

样本分支DAG:

来自气流导入DAG
从airflow.operators.dummy_operator导入dummy operator
从afflow.operators.python_operator导入BranchPythonOperator
从日期时间导入日期时间
从随机导入randint
默认参数={
“所有者”:“气流”,
“开始日期”:日期时间(2018年8月1日)
dag=dag(
“分支测试”,
默认参数=默认参数,
计划时间间隔=“****”,
catchup=错误)
#这两个函数仅用于保护任务不被作为分支运算符的直接依赖项跳过
to_do_work=dummy操作员(dag=dag,task\u id='to_do_work')
to_skip_work=dummy运算符(dag=dag,task_id='to_skip_work')
def分支_fn():
如果randint(0,1)=1,则返回到\u do\u work.task\u id,否则返回到\u skip\u work.task\u id
task_1=DummyOperator(dag=dag,task_id='task_1')
task_2=DummyOperator(dag=dag,task_id='task_2')
work=dummy运算符(dag=dag,task\u id='work')
branch=BranchPythonOperator(dag=dag,task\u id='branch',python\u callable=branch\u fn)
final=dummy操作符(dag=dag,task\u id=“final”,trigger\u rule=“all\u done”)
任务1>>分支>>完成工作>>工作>>最终
分支>>跳过工作>>最终
任务1>>任务2>>最终

我通过执行
final
任务来检查上游实例的状态,从而使其正常工作。我发现访问它们的状态的唯一方法是查询数据库,这并不漂亮

##有问题代码的附加导入
#从气流导入气流异常
#从airflow.models导入TaskInstance
#从afflow.operators.python_operator导入PythonOperator
#从airflow.settings导入会话
#从airflow.utils.state导入状态
#从airflow.utils.trigger\u规则导入TriggerRule
定义所有上游\u成功\u或跳过(dag、任务、任务\u实例、**上下文):
"""
直接查找上游任务实例,并统计有多少实例未处于首选状态。
如果没有非首选状态的实例,则返回True。
"""
上游任务id=[t.task\u任务中t的id.get\u直接亲属(上游=真)]
会话=会话()
查询=(会话)
.query(TaskInstance)
.过滤器(
TaskInstance.dag_id==dag.dag_id,
TaskInstance.execution\u date.in.([task\u instance.execution\u date]),
TaskInstance.task\u id.in\u(上游任务\u id)
)
)
上游任务实例=query.all()
不满意的_任务_实例=[ti代表上游_任务_实例中的ti,如果ti.state不在[state.SUCCESS,state.SKIPPED]]
打印(不满意的任务实例)
返回len(不满意的任务实例)==0
最终定义fn(**上下文):
"""
如果上游任务实例具有不需要的状态,则失败
"""
如果并非所有上游都成功或跳过(**上下文):
引发AirflowException(“并非所有上游任务都成功。”)
#做事
#将在上游任务实例完成(包括失败)时运行
最终=蟒蛇算子(
dag=dag,
任务\u id=“最终”,
trigger\u rule=TriggerRule.ALL\u完成,
python\u callable=final\u fn,
提供(上下文=真)

我在原来的基础上开发了自定义ShortCircuitOperator:

类ShortCircuitOperator(PythonOperator,SkipMixin):
"""
仅当满足条件时才允许工作流继续。否则
工作流“短路”和仅依赖此操作员的下游任务
被跳过。
ShortCircuit运算符派生自Python运算符。它计算
如果条件为False,则条件和短路工作流。是否
仅依赖此运算符的下游任务将标记为“跳过”状态。
如果条件为真,则下游任务将正常进行。
条件由“python\u callable”的结果决定。
"""
def find_tasks_to_skip(self、task、find_tasks=None):
如果未找到\u任务:
找到的任务=[]
直接亲属=任务。获取直接亲属(上游=False)
对于直系亲属中的t:
如果len(t.上游任务ID)==1:
已找到\u任务。追加(t)
self.find_tasks_to_skip(t,find_tasks)
返回找到的任务
def执行(自身、上下文):
条件=超级(ShortCircuitOperator,self)。执行(上下文)
def fn_short_circuit(**context):
    if <<<some condition>>>:
        raise AirflowSkipException("Skip this task and individual downstream tasks while respecting trigger rules.")

check_date = PythonOperator(
    task_id="check_if_min_date",
    python_callable=_check_date,
    provide_context=True,
    dag=dag,
)

task1 = DummyOperator(task_id="task1", dag=dag)
task2 = DummyOperator(task_id="task2", dag=dag)
work = DummyOperator(dag=dag, task_id='work')
short = ShortCircuitOperator(dag=dag, task_id='short_circuit', python_callable=fn_short_circuit
final_task = DummyOperator(task_id="final_task",
    trigger_rule='none_failed',
    dag=dag)


task_1 >> short >> work >> final_task
task_1 >> task_2 >> final_task