web-dev-qa-db-fra.com

Tâches dynamiques de flux d'air lors de l'exécution

D'autres questions sur les "tâches dynamiques" semblent aborder la construction dynamique d'un DAG au moment de la planification ou de la conception. Je suis intéressé par l'ajout dynamique de tâches à un DAG pendant l'exécution.

from airflow import DAG
from airflow.operators.dummy_operator import DummyOperator
from airflow.operators.python_operator import PythonOperator
from datetime import datetime

dag = DAG('test_dag', description='a test',
          schedule_interval='0 0 * * *',
          start_date=datetime(2018, 1, 1),
          catchup=False)

def make_tasks():
    du1 = DummyOperator(task_id='dummy1', dag=dag)
    du2 = DummyOperator(task_id='dummy2', dag=dag)
    du3 = DummyOperator(task_id='dummy3', dag=dag)
    du1 >> du2 >> du3

p = PythonOperator(
    task_id='python_operator',
    dag=dag,
    python_callable=make_tasks)

Cette implémentation naïve ne semble pas fonctionner - les tâches factices n'apparaissent jamais dans l'interface utilisateur.

Quelle est la bonne façon d'ajouter de nouveaux opérateurs au DAG pendant l'exécution? C'est possible?

17
Kirk Broadhurst

Il n'est pas possible de modifier le DAG lors de son exécution (sans beaucoup de travail).

Le dag = DAG(... est repris en boucle par le planificateur. Il aura une instance de tâche 'python_operator' dedans. Cette instance de tâche est planifiée dans une exécution dag et exécutée par un travailleur ou un exécuteur. Étant donné que les modèles DAG dans la base de données Airflow ne sont mis à jour que par le planificateur, ces tâches factices ajoutées ne seront pas conservées dans le DAG ni planifiées pour s'exécuter. Ils seront oubliés à la sortie du travailleur. Sauf si vous copiez tout le code du planificateur concernant la persistance et la mise à jour du modèle… mais cela sera annulé la prochaine fois que le planificateur visitera le fichier DAG pour l'analyse, ce qui pourrait se produire une fois par minute, une fois par seconde ou plus rapidement selon le nombre d'autres Les fichiers DAG doivent être analysés.

Airflow veut en fait que chaque DAG conserve approximativement la même disposition entre les exécutions. Il souhaite également recharger/analyser les fichiers DAG en permanence. Donc, bien que vous puissiez créer un fichier DAG qui, à chaque exécution, détermine les tâches de manière dynamique en fonction de certaines données externes (de préférence mises en cache dans un fichier ou un module pyc, et non des E/S réseau comme une recherche de base de données, vous ralentirez toute la boucle de planification pour tous les DAG) ce n'est pas un bon plan car votre graphique et votre arborescence deviendront tous confus, et votre analyse du planificateur sera plus taxée par cette recherche.

Vous pouvez faire exécuter l'appelable à chaque tâche…

def make_tasks(context):
    du1 = DummyOperator(task_id='dummy1', dag=dag)
    du2 = DummyOperator(task_id='dummy2', dag=dag)
    du3 = DummyOperator(task_id='dummy3', dag=dag)
    du1.execute(context)
    du2.execute(context)
    du3.execute(context)

p = PythonOperator(
    provides_context=true,

Mais c'est séquentiel, et vous devez savoir comment utiliser python pour les rendre parallèles (utiliser les futurs?) Et si une exception se déclenche, la tâche entière échoue. Elle est également liée à un exécuteur ou travailleur afin de ne pas utiliser la répartition des tâches de flux d'air (kubernetes, mesos, céleri).

L'autre façon de travailler avec ceci est d'ajouter un nombre fixe de tâches (le nombre maximal), et d'utiliser le ou les appelables pour court-circuiter les tâches inutiles ou les arguments Push avec xcom pour chacune d'entre elles, en changeant leur comportement au moment de l'exécution mais sans changer le DAG.

5
dlamblin

J'apprécie tout le travail que tout le monde a fait ici car j'ai le même défi de créer des DAG structurés dynamiquement. J'ai fait suffisamment d'erreurs pour ne pas utiliser de logiciel contre sa conception. Si je ne peux pas inspecter l'ensemble de l'interface utilisateur et faire un zoom avant et arrière, utilisez essentiellement les fonctionnalités de flux d'air, qui sont la principale raison pour laquelle je l'utilise de toute façon. Je peux simplement écrire du code de multitraitement dans une fonction et en finir aussi.

Cela étant dit, ma solution est d'utiliser un gestionnaire de ressources tel que le verrouillage redis et d'avoir un DAG qui écrit dans ce gestionnaire de ressources avec des données sur ce qu'il faut exécuter, comment exécuter etc; et avoir un autre DAG ou des DAG qui s'exécutent à certains intervalles interrogeant le gestionnaire de ressources, les verrouillant avant de les exécuter et les supprimant à la fin. De cette façon, j'utilise au moins le flux d'air comme prévu, même si ses spécifications ne répondent pas exactement à mes besoins. Je décompose le problème en morceaux plus définissables. Les solutions sont créatives mais elles sont contre la conception et non testées par les développeurs. Ils disent spécifiquement avoir des flux de travail structurés fixes. Je ne peux pas contourner le code qui n'est pas testé et contre la conception, sauf si je réécris le code de flux d'air de base et me teste moi-même. Je comprends que ma solution apporte de la complexité avec le verrouillage et tout ça, mais au moins je connais les limites de cela.

1
gman112358

Concernant votre exemple de code, vous n'appelez jamais votre fonction qui enregistre vos tâches dans votre DAG.

Pour avoir une sorte de tâches dynamiques, vous pouvez avoir un seul opérateur qui fait quelque chose de différent en fonction d'un état ou vous pouvez avoir une poignée d'opérateurs qui peuvent être ignorés en fonction de l'état, avec un ShortCircuitOperator.

1
Antoine Augusti