Я придумав спосіб створення робочих процесів на основі результатів попередніх завдань.
В основному, що ви хочете зробити, це мати два підтеги з наступним:
- Xcom натискає список (або що-небудь, що потрібно для подальшого створення динамічного робочого процесу) у підтезі, який виконується першим (див. Test1.py
def return_list()
)
- Передайте основний об’єкт dag як параметр другому підпрограмі
- Тепер, якщо у вас є основний об’єкт 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 pull частини проблем, якщо одночасно працює більше одного екземпляра дага, але тоді ви, мабуть, використовуєте унікальний ключ або щось подібне для однозначної ідентифікації xcom значення, яке ви хочете. Ймовірно, можна було б оптимізувати 3. крок, щоб бути впевненим на 100%, щоб отримати конкретне завдання поточного основного дага, але для мого використання це працює досить добре, я думаю, що для використання 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