通过变量执行动态循环以创建气流任务是否是一种好方法?

时间:2019-03-29 06:16:33

标签: python airflow

我有一个简单的气流DAG,可以说2个任务。像这样的东西:

newDirToLoad = Variable.get("path")
filesInDir = next(os.walk(newDirToLoad))[2] 

for f in filesInDir:
    task1 = BashOperator(
        task_id = "load_for_" + str(f),
        params = {"fileToProcess" : newDirToLoad + "/" + f}
        # ...
    )

    task1 = BashOperator(
        # ...
    )
    task1 >> task2

此处 path 变量最初设置为某个虚拟目录,以使我的Dag在创建Dag时不会失败。 在某个时候在“ data / to / load /”目录下创建了一个包含文件的新目录之后,我在某个地方编写了一个脚本,该脚本将触发airflow variables -set path data/to/load/$newDir,然后触发airflow trigger_dag myDag。这工作得很好,我看到气流GUI中的任务数与$ newDir中存在的文件数相同。但是我认为这是一种调整,允许使用 Variable 功能创建动态任务。有什么好的方法吗?为成功创建Dag,将path变量初始设置为某个虚拟目录是一种不好的做法吗?

1 个答案:

答案 0 :(得分:0)

实际上是可能的,而且非常方便。

我建议您看看天文学家团队的这篇博客文章:Dynamically Generating DAGs in Airflow

TL; DR,您可以编写如下内容:

customers = Variable.get("customers_list")
for customer in customers:
    dag = DAG(dag_id=f"dag_for_{customer}")

    run_first = DummyOperator(
        task_id='run_this_first',
        dag=dag
    )
    # for iteration purposes
    previous = run_first

    for step in Variable.get("customers_steps"):
        run_this = DummyOperator(
            task_id=f'run_{step}',
            dag=dag
        )
        previous >> run_this
        previous = run_this

    # From that point, the DAG is complete
    # Now, you need to put it in the module globals

    globals()[f"dag_for_{customer}"] = dag

之所以可行,是因为Airflow在其扫描的模块中查找DAG对象。在这种情况下,您只需将多个DAG集成到一个模块中,就可以了。

一些优缺点:

优点:

  • 从业务角度来看,将其提供的关注点分离可能非常有用。在分离客户的示例中,您最终可以只编辑可变内容,以及Airflow生成/删除DAG的花费。
  • 对于任务,同样的事情
  • 该示例使用变量是因为您要使用它,但实际上它可以接受所需的任何列表,而它是一个硬编码的列表或查询的结果。

缺点:

  • 请记住,您正在运行时生成DAG,并且您的模块不包含任何静态DAG。如果出于某种原因希望导入DAG,则必须在从另一个模块的导入中使用一些反射,但这似乎是非常罕见的情况
  • 如果列表很大,则重建DAG的列表可能会很长。您可能需要将DAG切割成较小的DAG,并对生成DAG的列表进行分区。
  • 如果DAG随时间变化太多,那么您将很难保留相关日志,并且计划程序可能很难跟踪任务触发

享受!