如何通过气流实现更复杂的dag调度?

时间:2019-04-15 17:51:38

标签: airflow

气流使固定间隔的作业变得容易。这篇文章寻求有关如何处理更复杂的调度要求的建议。

例如,假设我有从SFTP服务器提取文件并对它们执行某些操作的进程。源仅发布文件M-F。我希望dag表现为以下方式:

  • 仅运行M-F;
  • 在星期一,从execution_date - 0- 1- 2查找文件
  • 星期二至周五,只寻找execution date - 0吗?

似乎实现起来不切实际,我需要做的只是设计它来提取碰巧存在的所有文件并每天运行,而无需参考特定文件。

问题是,如果我可以指定由execution_date驱动的文件,那么我可以确切地看到已提取和未提取的内容,并可以使用重试功能。

想到的一种方法是每星期创建7个dag。但是我不喜欢那个主意。

另一种情况是,我是否希望该流程在每月的第二个星期日运行。有什么办法可以做这种事情?

编辑: 我认为实现此目的的最干净的方法是将dag设计为始终拉出日期为execution_date的文件,但要直到星期一才触发sat和sun运行(并使用Trigger dag运算符这样做),并且使用带有BranchOperator和TriggerDagOperator的控制器dag来实现此目的。

2 个答案:

答案 0 :(得分:2)

将DAG的var array1 = [ [1, 4, 6, 78], [5, 3, 9, 21], [11, 77, 9, 20], ]; var arr2 = [].concat.apply([], array1); console.log(arr2);设置为<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>,从星期一到星期五的每周的00:00运行。根据需要调整时间(前两个零)。

接下来,使用'schedule_interval':作为DAG的输入方式。因此,在星期一,将执行DAG,并使用'0 0 * * 1-5'BranchPythonOperatorexecution_date - 0查找文件。星期二至星期五,它只会查找execution_date - 1

我创建了一个简单的示例来向您展示我的意思。我希望这是一个充分的例子。让我知道是否可以进一步提供帮助。

execution_date - 2

example graph view

答案 1 :(得分:0)

Zack的答案有助于解决此问题(因为必须使用分支运算符),但我要解决的解决方案是使用TriggerDagRunOperator

这是我为测试此方法而构建的dags。

目标达空

def alert(ti, **kwargs):
    message = f"Execution date is {ti.execution_date}"
    print(message)

with target_dag:
    PythonOperator(
        python_callable=alert,
        task_id='target_task',
        provide_context=True,
    )

触发dag

def check_day(ti, **kwargs):
    execution_date = ti.execution_date
    if execution_date.minute % 7 == 0:
        return ['weekday_trigger', 'saturday_trigger', 'sunday_trigger']
    elif execution_date.minute % 7 in range(1, 5):
        return ['weekday_trigger']
    else:
        return []

with trigger_dag:
    check_day_task = BranchPythonOperator(
        task_id='check_day_task',
        python_callable=check_day,
        provide_context=True,
    )

    weekday_trigger = TriggerDagRunOperator(
        task_id='weekday_trigger',
        trigger_dag_id='target_dag',
        execution_date='{{ execution_date }}'
    )
    saturday_trigger = TriggerDagRunOperator(
        task_id='saturday_trigger',
        trigger_dag_id='target_dag',
        execution_date='{{ execution_date + macros.timedelta(days=-1) }}'
    )
    sunday_trigger = TriggerDagRunOperator(
        task_id='sunday_trigger',
        trigger_dag_id='target_dag',
        execution_date='{{ execution_date + macros.timedelta(days=-2) }}'
    )

    check_day_task >> [weekday_trigger, saturday_trigger, sunday_trigger]

为什么不只使用分支运算符?

我之所以喜欢这种方法,是因为我的目标dag不需要关心复杂的调度。它只需要关心执行日期。碰巧的是,在星期一,我们除了execution_date - 1还要执行execution_date - 2execution_date。但无论如何,目标dag的操作方式相同:它基于execution_date做特定的事情。

如果我尝试将分支运算符合并到目标dag中,它将很快变得混乱。例如。如果您的目标任务有4个任务,那么您需要在星期一将这些任务重复两次。此外,dag运行历史记录的树形视图很丑陋,有很多跳过的任务,回填可能很奇怪。

总结

因此,在非星期一的工作日,我们的触发器dag触发target_dag的执行日期与触发器dag相同。在周末,触发dag不会触发任何操作。在星期一和星期一,它会执行3次target_dag运行。

注意:在测试计划的运行中,我用了几分钟来模拟几天。

这是trigger_dag dag的图形视图: graph view of trigger dag

主要任务的树视图保持简洁: tree view of target dag