Python 气流中的动态任务定义

Python 气流中的动态任务定义,python,bash,airflow,orchestration,Python,Bash,Airflow,Orchestration,我目前正在尝试使用Airflow来编排一个流程,其中一些操作符是动态定义的,并且依赖于另一个(早期)操作符的输出 在下面的代码中,t1使用新记录更新文本文件(这些记录实际上是从外部队列读取的,但为了简单起见,我在这里将它们硬编码为a、B和C)。然后,我想为从该文本文件读取的每条记录创建单独的运算符。这些操作符将分别创建目录A、B和C,在Airflow UI中,它们将被视为单独的bash进程create_directory_A、create_directory_B和create_directory

我目前正在尝试使用Airflow来编排一个流程,其中一些操作符是动态定义的,并且依赖于另一个(早期)操作符的输出

在下面的代码中,t1使用新记录更新文本文件(这些记录实际上是从外部队列读取的,但为了简单起见,我在这里将它们硬编码为a、B和C)。然后,我想为从该文本文件读取的每条记录创建单独的运算符。这些操作符将分别创建目录A、B和C,在Airflow UI中,它们将被视为单独的bash进程create_directory_A、create_directory_B和create_directory_C

dag = DAG('Test_DAG',
          description="Lorem ipsum.",
          start_date=datetime(2017, 3, 20),
          schedule_interval=None,
          catchup=False)


def create_text_file(list_of_rows):
    text_file = open('text_file.txt', "w")
    for row in list_of_rows:
        text_file.write(row + '\n')
    text_file.close()


def read_text():
    txt_file = open('text_file.txt', 'r')
    return [element for element in txt_file.readlines()]


t1 = PythonOperator(
    task_id='Create_text_file',
    python_callable=create_text_file,
    op_args=[['A', 'B', 'C']],
    dag=dag
)

for row in read_text():
    t2 = BashOperator(
        task_id='Create_directory_{}'.format(row),
        bash_command="mkdir {{params.dir_name}}",
        params={'dir_name': row},
        dag=dag
    )

    t1 >> t2

在中,我可以看到调度程序将定期执行它[DAG],以反映任何更改。这是否意味着存在这样一种风险:即使我的t1操作符在t2之前执行,在更新之前也会为记录列表创建bash操作符(就像在评估DAG时那样)?

此代码实际上将创建
t2
的一个实例,该实例将由bash操作符使用从
read\u text()获取的最后一行
构建。我肯定这不是你想要的


更好的方法是为
t2
操作符创建一个单独的DAG,该DAG在
t1
写入文件时触发。关于这一点,有一个问题可能会有所帮助:

您不能根据上游任务的输出动态创建任务。你把时间表和执行时间搞混了。DAG定义和任务在计划时间创建。DAG运行和任务实例在执行时创建。只有任务实例才能生成输出

气流调度器将在计划时间使用
text_file.txt
包含的任何内容构建动态图形。然后将这些任务发送给工人

工作者最终将执行
t1
任务实例并创建一个新的
text_file.txt
,但此时,调度程序已经计算出
t2
任务列表,并将其发送给工作者

因此,无论最新的
t1
任务实例转储到
text\u file.txt
中,都将在计划程序下次决定运行DAG时使用


如果您的任务很快,并且您的工作人员没有积压,则这将是上一次DAG运行的内容。如果它们是积压的,
text\u file.txt
内容可能会过时,如果您真的运气不好,调度程序会在任务实例写入文件时读取该文件,您将从
read\u text()

中获得不完整的数据,谢谢Steve。我意识到我在
t1
中遗漏了额外的方括号。目前,代码确实为从
read\u text()
读取的所有行生成
t2
。它得到的行列表是否有过时的风险?啊,好的。我仍然认为一个单独的DAG会更干净,更容易维护,我不会依赖它的工作,因为它是。多个DAG在Airflow上非常常见/什么可能是一种好的方法:查询时间表上的表,如果找到,则为每一行运行任务?感谢您的解释!我们如何确保t1在t2之前运行?这与子DAG有关吗?这就是
t1>>t2
所做的-它建立了一个任务的有向无环图(DAG),描述了任务应该按什么顺序运行。