Skip to content

Commit f6e0900

Browse files
authored
Prevent using trigger_rule="always" in a dynamic mapped task (#43368)
1 parent 1c38b2a commit f6e0900

3 files changed

Lines changed: 47 additions & 5 deletions

File tree

docs/apache-airflow/authoring-and-scheduling/dynamic-task-mapping.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ The grid view also provides visibility into your mapped tasks in the details pan
8484

8585
Although we show a "reduce" task here (``sum_it``) you don't have to have one, the mapped tasks will still be executed even if they have no downstream tasks.
8686

87+
.. warning:: ``TriggerRule.ALWAYS`` cannot be utilized in expanded tasks
88+
89+
Assigning ``trigger_rule=TriggerRule.ALWAYS`` in expanded tasks is forbidden, as expanded parameters will be undefined with the task's immediate execution.
90+
This is enforced at the time of the DAG parsing, and will raise an error if you try to use it.
91+
8792
Task-generated Mapping
8893
----------------------
8994

task_sdk/src/airflow/sdk/definitions/taskgroup.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
TaskAlreadyInTaskGroup,
3838
)
3939
from airflow.sdk.definitions.node import DAGNode
40+
from airflow.utils.trigger_rule import TriggerRule
4041

4142
if TYPE_CHECKING:
4243
from airflow.models.expandinput import ExpandInput
@@ -195,10 +196,15 @@ def task_group(self, value: TaskGroup | None):
195196

196197
def __iter__(self):
197198
for child in self.children.values():
198-
if isinstance(child, TaskGroup):
199-
yield from child
200-
else:
201-
yield child
199+
yield from self._iter_child(child)
200+
201+
@staticmethod
202+
def _iter_child(child):
203+
"""Iterate over the children of this TaskGroup."""
204+
if isinstance(child, TaskGroup):
205+
yield from child
206+
else:
207+
yield child
202208

203209
def add(self, task: DAGNode) -> DAGNode:
204210
"""
@@ -574,6 +580,14 @@ def __init__(self, *, expand_input: ExpandInput, **kwargs: Any) -> None:
574580
super().__init__(**kwargs)
575581
self._expand_input = expand_input
576582

583+
def __iter__(self):
584+
from airflow.models.abstractoperator import AbstractOperator
585+
586+
for child in self.children.values():
587+
if isinstance(child, AbstractOperator) and child.trigger_rule == TriggerRule.ALWAYS:
588+
raise ValueError("Tasks in a mapped task group cannot have trigger_rule set to 'ALWAYS'")
589+
yield from self._iter_child(child)
590+
577591
def iter_mapped_dependencies(self) -> Iterator[DAGNode]:
578592
"""Upstream dependencies that provide XComs used by this mapped task group."""
579593
from airflow.models.xcom_arg import XComArg

tests/decorators/test_task_group.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
import pendulum
2323
import pytest
2424

25-
from airflow.decorators import dag, task_group
25+
from airflow.decorators import dag, task, task_group
2626
from airflow.models.expandinput import DictOfListsExpandInput, ListOfDictsExpandInput, MappedArgument
2727
from airflow.operators.empty import EmptyOperator
2828
from airflow.utils.task_group import MappedTaskGroup
29+
from airflow.utils.trigger_rule import TriggerRule
2930

3031

3132
def test_task_group_with_overridden_kwargs():
@@ -133,6 +134,28 @@ def tg():
133134
assert str(ctx.value) == "no arguments to expand against"
134135

135136

137+
@pytest.mark.db_test
138+
def test_expand_fail_trigger_rule_always(dag_maker, session):
139+
@dag(schedule=None, start_date=pendulum.datetime(2022, 1, 1))
140+
def pipeline():
141+
@task
142+
def get_param():
143+
return ["a", "b", "c"]
144+
145+
@task(trigger_rule=TriggerRule.ALWAYS)
146+
def t1(param):
147+
return param
148+
149+
@task_group()
150+
def tg(param):
151+
t1(param)
152+
153+
with pytest.raises(
154+
ValueError, match="Tasks in a mapped task group cannot have trigger_rule set to 'ALWAYS'"
155+
):
156+
tg.expand(param=get_param())
157+
158+
136159
def test_expand_create_mapped():
137160
saved = {}
138161

0 commit comments

Comments
 (0)