I'm newer to airflow, but I'm having difficulties really understanding how to pass small xcom values around. Sometimes, this seems to work without an issue; other times, it takes me hours. Here's an example that has really been getting me.
I'm trying to trigger an external DAG, and I need to pass a number as a param to the external dag. I don't know this number, but I get it from a task in my dag. How can I pass this as a conf/param to the triggered DAG?
This is probably easiest to understand through an example:
import datetime
from airflow import DAG
from airflow.decorators import task
from airflow.models import Param
from airflow.operators.bash import BashOperator
from airflow.operators.trigger_dagrun import TriggerDagRunOperator
with DAG(
dag_id="example_trigger_target_dag",
schedule_interval=None,
start_date=datetime.datetime(year=2022, month=1, day=1),
catchup=False,
tags=["example"],
params={
"a_number": Param(
1,
type="number",
),
},
) as target_dag:
bash_task = BashOperator(
task_id="bash_task",
bash_command="echo 'Here is some number: {{ params.a_number }}'",
)
with DAG(
dag_id="example_trigger_controller_dag",
schedule_interval=None,
start_date=datetime.datetime(year=2022, month=1, day=1),
catchup=False,
tags=["example"],
params={
"different_number": Param(
2,
type="number",
),
},
) as trigger_dag:
trigger_with_2 = TriggerDagRunOperator(
task_id="test_trigger_dagrun_with_2",
trigger_dag_id="example_trigger_target_dag", # Ensure this equals the dag_id of the DAG to trigger
conf={
"a_number": 2,
},
)
##############################
# I'd expect this to work, but it doesn't.
# error: during build
# airflow.exceptions.AirflowException: conf parameter should be JSON Serializable
##########
# @task
# def get_number_3() -> int:
# return 3
#
# number_3_from_task = get_number_3()
# trigger_with_3 = TriggerDagRunOperator(
# task_id="test_trigger_dagrun_with_3",
# trigger_dag_id="example_trigger_target_dag", # Ensure this equals the dag_id of the DAG to trigger
# conf={
# "a_number": number_3_from_task,
# },
# )
##############################
# This was only in response to the above. It feels worse and uglier, but I'd have made do with it. But it, too, doesn't work.
# error during dag run
# Failed validating 'type' in schema:
# {'type': 'number'}
##########
@task
def get_number_4() -> int:
return 4
number_4_from_task = get_number_4()
trigger_with_4 = TriggerDagRunOperator(
task_id="test_trigger_dagrun_with_4",
trigger_dag_id="example_trigger_target_dag", # Ensure this equals the dag_id of the DAG to trigger
wait_for_completion=True,
conf={
"a_number": "{{ ti.xcom_pull(task_ids='get_number_4', key='return_value') | int }}",
},
)
number_4_from_task >> trigger_with_4
##############################
# This works without an issue.
# I've tried wrapping the TriggerDagRunOperator in a decorated task, but I have issues waiting for that task to finish.
# Also, it doesn't seem to solve the issue I'm having here, anyways.
##########
@task
def print_a_number(your_num: int) -> str:
text = f"wow, a number: {your_num}"
print(text)
return text
print_a_number(number_4_from_task)