Воздушный поток-как передать переменную xcom в функцию Python

мне нужно ссылаться на переменную, возвращаемую BashOperator. Возможно, я поступаю неправильно, так что, пожалуйста, прости меня. В моем task_archive_s3_file, мне нужно получить имя файла из get_s3_file. Задача просто печатает {{ ti.xcom_pull(task_ids=submit_file_to_spark) }} в виде строки вместо значения.

если я использую bash_command значение для правильной печати.

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

3 ответов


Шаблоны типа {{ ti.xcom_pull(...) }} может использоваться только внутри параметров, поддерживающих шаблоны, или они не будут отображаться до выполнения. Вижу template_fields и template_ext атрибуты PythonOperator и BashOperator.

так templates_dict это то, что вы используете для передачи шаблонов вашему оператору python:

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') }}" })

однако в случае извлечения значения XCom другая альтернатива просто использует TaskInstance объект, доступный вам через контекст:

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,

Upvoted как вопрос, так и ответ, но я думаю, что это можно сделать немного более понятным для тех пользователей, которые просто хотят передать небольшие объекты данных между PythonOperator задачи в их DAG. Ссылка на этот вопрос и этот пример XCom у меня к следующему решению. Супер просто:

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

Я не уверен, почему это работает, но это делает. Несколько вопросов для сообщества:

  • что происходит с ti здесь? Как это построен в **kwargs?
  • и provide_context=True необходимо для обеих функций?

любые изменения, чтобы сделать этот ответ более ясным, очень приветствуются!


вот еще одно простое решение. Это модифицированная версия примера @Aaron, но я использовал пара ключ-значение при общении:

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

DAG = DAG(
  dag_id='simple_xcom',
  start_date=datetime(2017, 10, 26),
  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(
    task_id='pull_task', 
    python_callable=pull_function,
    provide_context=True,
    dag=DAG)

push_task >> pull_task