Airflow 气流任务能否在运行时动态生成DAG?

Airflow 气流任务能否在运行时动态生成DAG?,airflow,airflow-scheduler,Airflow,Airflow Scheduler,我有一个上传文件夹,可以不定期上传。对于每个上传的文件,我希望生成一个特定于该文件的DAG 我的第一个想法是使用一个监控上传文件夹的文件传感器来实现这一点,并在存在新文件的情况下触发一个创建单独DAG的任务。概念上: Sensor_DAG (FileSensor -> CreateDAGTask) |-> File1_DAG (Task1 -> Task2 -> ...) |-> File2_DAG (Task1 -> Task2 -> ...) 在

我有一个上传文件夹,可以不定期上传。对于每个上传的文件,我希望生成一个特定于该文件的DAG

我的第一个想法是使用一个监控上传文件夹的文件传感器来实现这一点,并在存在新文件的情况下触发一个创建单独DAG的任务。概念上:

Sensor_DAG (FileSensor -> CreateDAGTask)

|-> File1_DAG (Task1 -> Task2 -> ...)
|-> File2_DAG (Task1 -> Task2 -> ...)
在我的初始实现中,
CreateDAGTask
是一个
PythonOperator
,它通过将DAG全局变量放置在全局名称空间()中来创建它们,如下所示:

来自气流导入DAG
从airflow.operators.dummy_operator导入dummy operator
从afflow.operators.python_operator导入PythonOperator
从afflow.contrib.sensors.file\传感器导入文件传感器
从datetime导入datetime,timedelta
从pathlib导入路径
UPLOAD_LOCATION=“/opt/files/UPLOAD”
#以下传感器的动态DAG生成任务代码
def为文件生成文件(位置=上传位置,**kwargs):
dags=[]
对于路径(位置).glob('*')中的文件路径:
dag_name=f“进程{filepath.name}”
dag=dag(dag_名称,计划_间隔=“@once”,默认参数={
“依靠过去”:没错,
“开始日期”:日期时间(2020年7月15日),
“重试”:1,
“重试延迟”:时间增量(小时=12)
},catchup=False)
dag_task=dummy操作符(dag=dag,task_id=f“start{dag_name}”)
附加(dag)
#尝试将DAG放入globals(),但这不起作用
globals()[dag_name]=dag
返回DAG
然后,主DAG通过
PythonOperator
调用此逻辑:

# File-sensing DAG
default_args = {
    "depends_on_past" : False,
    "start_date"      : datetime(2020, 7, 16),
    "retries"         : 1,
    "retry_delay"     : timedelta(hours=5),
}
with DAG("Sensor_DAG", default_args=default_args,
         schedule_interval= "50 * * * *", catchup=False, ) as sensor_dag:

    start_task  = DummyOperator(task_id="start")
    stop_task   = DummyOperator(task_id="stop")
    sensor_task = FileSensor(task_id="my_file_sensor_task",
                             poke_interval=60,
                             filepath=UPLOAD_LOCATION)
    process_creator_task = PythonOperator(
        task_id="process_creator",
        python_callable=generate_dags_for_files,
    )
    start_task >> sensor_task >> process_creator_task >> stop_task
但是这不起作用,因为当
进程\u创建者\u任务
运行时,全局变量已经被气流解析了。解析时间之后的新全局变量是不相关的

临时解决办法 根据,我可以通过完全省略
FileSensor
任务,让气流在每个调度程序心跳时生成每个文件任务,将传感器DAG替换为只执行
generate_dags_for_files
:Update:Nevermind,而这会在仪表板中创建DAG,实际执行会遇到以下问题:

generate_dags_for_files()
这意味着我不能再使用
FileSensor
poke_interval
参数来调节文件夹轮询的频率;相反,气流将在每次收集DAG时轮询文件夹

这是这里最好的款式吗

其他相关的堆栈溢出线程
  • 和:相同的用例,但公认的答案使用两个静态DAG,可能具有不同的参数
  • -accepted answer通过复杂的XCom设置动态创建任务,而不是DAG

简言之:如果任务写入的是
DagBag
读取的内容,则可以,但最好避免使用需要这样做的模式您试图在任务中自定义创建的任何DAG都应该是静态的、高度参数化的、有条件触发的DAG。,我非常感谢他对这个问题的指导

这就是说,在日益严重的笨手笨脚的情况下,无论一个想法多么糟糕,以下是可以实现问题所要求的方法:

  • 如果从变量()动态生成DAG,请修改该变量
  • 如果从配置文件列表中动态生成DAG,请将新的配置文件添加到从中提取配置文件的位置,以便在下一个DAG集合中生成新的DAG
  • 使用类似Jinja模板的方法在
    dags/
    文件夹中编写新的Python文件

要在任务运行后保留对其的访问权限,您必须保持新DAG定义稳定,并在以后的仪表板更新/DagBagcollection时可访问。否则,我就重读那篇文章;虽然它们在解析时会动态生成DAG,但我不相信任何示例都有动态创建DAG的任务。@Simon Podhajsky,因为python是一种基于解释器的语言,这当然可以通过元编程实现:如果您的
任务
以编程方式在Airflow的DAG目录中生成并写入有效的DAG文件,几分钟内它们将被拾取并显示在UI上。现在,它真的不必像生成
python
code那样困难:如果您编写一个python脚本(DAG定义文件),它根据从
变量读取的JSON输入生成DAG(具有预定义的结构/任务),然后只要通过气流任务更新
变量
,就会产生新的DAG。我认为这最接近你想要的:他不会在运行时生成新的DAG;但他正在运行时向DAG添加新的下游
任务
s(上游任务更新一个
变量
,并导致新的下游任务出现),但这里需要提醒一句:根据我对气流的经验(但不仅仅是构建和维护ETL平台),我建议你尽量远离这种魔法。IMO
DAG
s应该是不变的、持久的/可预测的:[i]DAG不应该神奇地出现和消失,而且[ii]更糟糕的是,DAG中的任务不应该出现和消失。否则,您的整个簿记(DAG、任务的历史记录)将受到影响,系统的可观察性/可调试性将受到影响