web-dev-qa-db-fra.com

Airflow - Comment passer une variable xcom à la fonction Python

Je dois référencer une variable renvoyée par un BashOperator. Je fais peut-être mal, alors pardonnez-moi s'il vous plaît. Dans mon task_archive_s3_file, Je dois obtenir le nom du fichier à partir de get_s3_file. La tâche affiche simplement {{ ti.xcom_pull(task_ids=submit_file_to_spark) }} sous forme de chaîne au lieu de la valeur.

Si j'utilise le bash_command, La valeur s'imprime correctement.

get_s3_file = PythonOperator(
    task_id='get_s3_file',
    python_callable=obj.func_get_s3_file,
    trigger_rule=TriggerRule.ALL_SUCCESS,
    dag=dag)

submit_file_to_spark = BashOperator(
    task_id='submit_file_to_spark',
    bash_command="echo 'hello world'",
    trigger_rule="all_done",
    xcom_Push=True,
    dag=dag)

task_archive_s3_file = PythonOperator(
    task_id='archive_s3_file',
#    bash_command="echo {{ ti.xcom_pull(task_ids='submit_file_to_spark') }}",
    python_callable=obj.func_archive_s3_file,
    params={'s3_path_filename': "{{ ti.xcom_pull(task_ids=submit_file_to_spark) }}" },
    dag=dag)

get_s3_file >> submit_file_to_spark >> task_archive_s3_file
23
luckytaxi

Des modèles tels que {{ ti.xcom_pull(...) }} ne peuvent être utilisés qu'à l'intérieur de paramètres prenant en charge les modèles, sinon ils ne seront pas rendus avant leur exécution. Voir le template_fields et template_ext attributs de PythonOperator et BashOperator .

Alors templates_dict est ce que vous utilisez pour passer des templates à votre python opérateur:

def func_archive_s3_file(**context):
    archive(context['templates_dict']['s3_path_filename'])

task_archive_s3_file = PythonOperator(
    task_id='archive_s3_file',
    dag=dag,
    python_callable=obj.func_archive_s3_file,
    provide_context=True,  # must pass this because templates_dict gets passed via context
    templates_dict={'s3_path_filename': "{{ ti.xcom_pull(task_ids='submit_file_to_spark') }}" })

Cependant, dans le cas de l'extraction d'une valeur XCom, une autre alternative consiste simplement à utiliser l'objet TaskInstance mis à votre disposition via le contexte:

def func_archive_s3_file(**context):
    archive(context['ti'].xcom_pull(task_ids='submit_file_to_spark'))

task_archive_s3_file = PythonOperator(
    task_id='archive_s3_file',
    dag=dag,
    python_callable=obj.func_archive_s3_file,
    provide_context=True,
28
Daniel Huang

J'ai voté à la fois la question et la réponse, mais je pense que cela peut être un peu plus clair pour les utilisateurs qui souhaitent simplement transmettre de petits objets de données entre des tâches PythonOperator dans leurs DAG. Référencer cette question et cet exemple XCom m'a conduit à la solution suivante. Super simple:

from airflow.models import DAG
from airflow.operators.python_operator import PythonOperator

DAG = DAG(
  dag_id='example_dag',
  start_date=datetime.now(),
  schedule_interval='@once'
)

def Push_function(**kwargs):
    ls = ['a', 'b', 'c']
    return ls

Push_task = PythonOperator(
    task_id='Push_task', 
    python_callable=Push_function,
    provide_context=True,
    dag=DAG)

def pull_function(**kwargs):
    ti = kwargs['ti']
    ls = ti.xcom_pull(task_ids='Push_task')
    print(ls)

pull_task = PythonOperator(
    task_id='pull_task', 
    python_callable=pull_function,
    provide_context=True,
    dag=DAG)

Push_task >> pull_task

Je ne sais pas pourquoi cela fonctionne, mais ça marche. Quelques questions pour la communauté:

  • Que se passe-t-il avec ti ici? Comment est-ce construit en **kwargs?
  • Est provide_context=True nécessaire pour les deux fonctions?

Toute modification visant à clarifier cette réponse est la bienvenue!

17
Aaron

Utilisé le même code et modifié params comme Startdate etc.

import airflow
from datetime import datetime, timedelta
from airflow.models import DAG
from airflow.operators.python_operator import PythonOperator

args = {
    'owner': 'Airflow',
    'start_date': airflow.utils.dates.days_ago(2),
}

DAG = DAG(
  dag_id='simple_xcom',
  default_args=args,
#  start_date=datetime(2019, 04, 21),
  schedule_interval="@daily",
  #schedule_interval=timedelta(1)
)

def Push_function(**context):
    msg='the_message'
    print("message to Push: '%s'" % msg)
    task_instance = context['task_instance']
    task_instance.xcom_Push(key="the_message", value=msg)

Push_task = PythonOperator(
    task_id='Push_task', 
    python_callable=Push_function,
    provide_context=True,
    dag=DAG)

def pull_function(**kwargs):
    ti = kwargs['ti']
    msg = ti.xcom_pull(task_ids='Push_task',key='the_message')
    print("received message: '%s'" % msg)

pull_task = PythonOperator(`enter code here`
    task_id='pull_task', 
    python_callable=pull_function,
    provide_context=True,
    dag=DAG)

Push_task >> pull_task
6
dan