Ich habe einen Weg gefunden, Workflows basierend auf dem Ergebnis früherer Aufgaben zu erstellen.
Grundsätzlich möchten Sie zwei Subtags mit den folgenden Elementen haben:
- Xcom verschiebt eine Liste (oder was auch immer Sie benötigen, um den dynamischen Workflow später zu erstellen) in den Subtag, der zuerst ausgeführt wird (siehe test1.py
def return_list()
).
- Übergeben Sie das Haupt-Dag-Objekt als Parameter an Ihr zweites Subdag
- Wenn Sie nun das Hauptobjekt dag haben, können Sie es verwenden, um eine Liste seiner Aufgabeninstanzen abzurufen. Aus dieser Liste von Aufgabeninstanzen können Sie eine Aufgabe des aktuellen Laufs herausfiltern, indem Sie
parent_dag.get_task_instances(settings.Session, start_date=parent_dag.get_active_runs()[-1])[-1]
) verwenden. Hier könnten wahrscheinlich weitere Filter hinzugefügt werden.
- Mit dieser Task-Instanz können Sie xcom pull verwenden, um den gewünschten Wert zu erhalten, indem Sie die dag_id für den ersten Unterag angeben:
dag_id='%s.%s' % (parent_dag_name, 'test1')
- Verwenden Sie die Liste / den Wert, um Ihre Aufgaben dynamisch zu erstellen
Jetzt habe ich dies in meiner lokalen Luftstrominstallation getestet und es funktioniert einwandfrei. Ich weiß nicht, ob das xcom-Pull-Teil Probleme haben wird, wenn mehr als eine Instanz des Dags gleichzeitig ausgeführt wird, aber dann würden Sie wahrscheinlich entweder einen eindeutigen Schlüssel oder ähnliches verwenden, um das xcom eindeutig zu identifizieren Wert, den Sie wollen. Man könnte wahrscheinlich den 3. Schritt optimieren, um 100% sicher zu sein, dass eine bestimmte Aufgabe des aktuellen Haupttags erhalten wird, aber für meine Verwendung funktioniert dies gut genug. Ich denke, man benötigt nur ein task_instance-Objekt, um xcom_pull zu verwenden.
Außerdem bereinige ich die xcoms für den ersten Subtag vor jeder Ausführung, um sicherzustellen, dass ich nicht versehentlich einen falschen Wert erhalte.
Ich kann es ziemlich schlecht erklären, also hoffe ich, dass der folgende Code alles klar macht:
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
und der Hauptworkflow:
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