Я придумал, как создавать рабочие процессы на основе результатов предыдущих задач.
По сути, вы хотите создать два вложенных тега со следующим:
- Xcom отправляет список (или то, что вам понадобится для создания динамического рабочего процесса позже) во вложенном теге, который выполняется первым (см. Test1.py
def return_list()
)
- Передайте основной объект dag в качестве параметра вашему второму subdag
- Теперь, если у вас есть основной объект dag, вы можете использовать его для получения списка его экземпляров задач. Из этого списка экземпляров задач вы можете отфильтровать задачу текущего запуска с помощью
parent_dag.get_task_instances(settings.Session, start_date=parent_dag.get_active_runs()[-1])[-1]
), возможно, здесь можно было бы добавить больше фильтров.
- С этим экземпляром задачи вы можете использовать xcom pull, чтобы получить нужное вам значение, указав dag_id для одного из первых вложенных тегов:
dag_id='%s.%s' % (parent_dag_name, 'test1')
- Используйте список / значение для динамического создания задач
Теперь я протестировал это в своей локальной установке воздушного потока, и он отлично работает. Я не знаю, будут ли проблемы с вытягивающей частью xcom, если одновременно запущено более одного экземпляра dag, но тогда вы, вероятно, либо используете уникальный ключ, либо что-то в этом роде, чтобы однозначно идентифицировать xcom ценность, которую вы хотите. Вероятно, можно было бы оптимизировать 3. шаг, чтобы быть на 100% уверенным в получении конкретной задачи текущего основного dag, но для моего использования это работает достаточно хорошо, я думаю, что для использования xcom_pull нужен только один объект task_instance.
Также я очищаю xcoms для первого субдага перед каждым выполнением, просто чтобы убедиться, что я случайно не получу неправильное значение.
Я плохо объясняю, поэтому надеюсь, что следующий код все прояснит:
test1.py
from airflow.models import DAG
import logging
from airflow.operators.python_operator import PythonOperator
from airflow.operators.postgres_operator import PostgresOperator
log = logging.getLogger(__name__)
def test1(parent_dag_name, start_date, schedule_interval):
dag = DAG(
'%s.test1' % parent_dag_name,
schedule_interval=schedule_interval,
start_date=start_date,
)
def return_list():
return ['test1', 'test2']
list_extract_folder = PythonOperator(
task_id='list',
dag=dag,
python_callable=return_list
)
clean_xcoms = PostgresOperator(
task_id='clean_xcoms',
postgres_conn_id='airflow_db',
sql="delete from xcom where dag_id='{{ dag.dag_id }}'",
dag=dag)
clean_xcoms >> list_extract_folder
return dag
test2.py
from airflow.models import DAG, settings
import logging
from airflow.operators.dummy_operator import DummyOperator
log = logging.getLogger(__name__)
def test2(parent_dag_name, start_date, schedule_interval, parent_dag=None):
dag = DAG(
'%s.test2' % parent_dag_name,
schedule_interval=schedule_interval,
start_date=start_date
)
if len(parent_dag.get_active_runs()) > 0:
test_list = parent_dag.get_task_instances(settings.Session, start_date=parent_dag.get_active_runs()[-1])[-1].xcom_pull(
dag_id='%s.%s' % (parent_dag_name, 'test1'),
task_ids='list')
if test_list:
for i in test_list:
test = DummyOperator(
task_id=i,
dag=dag
)
return dag
и основной рабочий процесс:
test.py
from datetime import datetime
from airflow import DAG
from airflow.operators.subdag_operator import SubDagOperator
from subdags.test1 import test1
from subdags.test2 import test2
DAG_NAME = 'test-dag'
dag = DAG(DAG_NAME,
description='Test workflow',
catchup=False,
schedule_interval='0 0 * * *',
start_date=datetime(2018, 8, 24))
test1 = SubDagOperator(
subdag=test1(DAG_NAME,
dag.start_date,
dag.schedule_interval),
task_id='test1',
dag=dag
)
test2 = SubDagOperator(
subdag=test2(DAG_NAME,
dag.start_date,
dag.schedule_interval,
parent_dag=dag),
task_id='test2',
dag=dag
)
test1 >> test2