我有一个上传文件夹,可以不定期上传。对于每个上传的文件,我都希望生成一个特定于该文件的DAG。
我的第一个想法是使用FileSensor来执行此操作,该FileSensor监视上传文件夹,并在存在新文件的情况下触发创建单独DAG的任务。从概念上讲:
Sensor_DAG (FileSensor -> CreateDAGTask)
|-> File1_DAG (Task1 -> Task2 -> ...)
|-> File2_DAG (Task1 -> Task2 -> ...)
在我最初的实现中,CreateDAGTask
是一个PythonOperator
,它通过将DAG全局变量放置在全局名称空间(see this SO answer)中来创建DAG全局变量,如下所示:
from airflow import DAG
from airflow.operators.dummy_operator import DummyOperator
from airflow.operators.python_operator import PythonOperator
from airflow.contrib.sensors.file_sensor import FileSensor
from datetime import datetime, timedelta
from pathlib import Path
UPLOAD_LOCATION = "/opt/files/uploaded"
# Dynamic DAG generation task code, for the Sensor_DAG below
def generate_dags_for_files(location=UPLOAD_LOCATION, **kwargs):
dags = []
for filepath in Path(location).glob('*'):
dag_name = f"process_{filepath.name}"
dag = DAG(dag_name, schedule_interval="@once", default_args={
"depends_on_past": True,
"start_date": datetime(2020, 7, 15),
"retries": 1,
"retry_delay": timedelta(hours=12)
}, catchup=False)
dag_task = DummyOperator(dag=dag, task_id=f"start_{dag_name}")
dags.append(dag)
# Try to place the DAG into globals(), which doesn't work
globals()[dag_name] = dag
return dags
然后,主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
但这不起作用,因为到process_creator_task
运行时,Airflow已经解析了全局变量。解析时间之后的新全局变量无关紧要。
每Airflow dynamic DAG and task Ids,我可以完全省略更新:没关系-尽管这确实在仪表板中创建了DAG,但实际执行遇到了"DAG seems to be missing"问题:FileSensor
任务,而让Airflow在每个调度程序脉动信号下生成按文件的任务,代替Sensor_DAG仅执行generate_dags_for_files
:
generate_dags_for_files()
这确实意味着我不再可以使用poke_interval
的{{1}}参数来调节文件夹轮询的频率;相反,Airflow每次收集DAG时都会轮询该文件夹。
这是最好的模式吗?
答案 0 :(得分:1)
简而言之:如果任务写了DagBag
的读取位置,是的,但是最好避免使用需要这样做的模式。 您试图在任务中自定义创建的任何DAG可能应该改为是静态的,参数化的,有条件触发的DAG。 y2k-shubham provides an excellent example of such a setup,对于他的指导,我深表感谢关于这个问题的评论。
也就是说,这是一种可以解决问题的方法,不管这个想法有多糟糕,都将使他们变得越来越无礼:
dags/
文件夹中编写一个新的Python文件。要在任务运行后保留对任务的访问权,必须保持新的DAG定义稳定并在以后的仪表板更新/ DagBag
集合中可访问。否则,the Airflow dashboard won't be able to render much about it.