-
Notifications
You must be signed in to change notification settings - Fork 16.4k
[AIP-34] TaskGroup: A UI task grouping concept as an alternative to SubDagOperator #10153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cce50ec
ad8e2b2
1f0cea0
2dcfd33
3ad1c62
4ec28d7
6ea4cde
45afedb
4e8a9c3
8090264
14023ab
96281c2
866b6c2
580384b
1888bd4
75de22b
3dd1f98
8dec3e8
55ed52f
ca24002
e39e203
c30668a
0c9ec6a
587ee03
55d052b
2b544f4
02dff21
0317413
01ccf02
d6fa4c3
cffe049
9157991
4c9464a
85c9f67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| """Example DAG demonstrating the usage of the TaskGroup.""" | ||
|
|
||
| from airflow.models.dag import DAG | ||
| from airflow.operators.dummy_operator import DummyOperator | ||
| from airflow.utils.dates import days_ago | ||
| from airflow.utils.task_group import TaskGroup | ||
|
|
||
| # [START howto_task_group] | ||
| with DAG(dag_id="example_task_group", start_date=days_ago(2)) as dag: | ||
| start = DummyOperator(task_id="start") | ||
|
|
||
| # [START howto_task_group_section_1] | ||
| with TaskGroup("section_1", tooltip="Tasks for section_1") as section_1: | ||
| task_1 = DummyOperator(task_id="task_1") | ||
| task_2 = DummyOperator(task_id="task_2") | ||
| task_3 = DummyOperator(task_id="task_3") | ||
|
|
||
| task_1 >> [task_2, task_3] | ||
| # [END howto_task_group_section_1] | ||
|
|
||
| # [START howto_task_group_section_2] | ||
| with TaskGroup("section_2", tooltip="Tasks for section_2") as section_2: | ||
| task_1 = DummyOperator(task_id="task_1") | ||
|
|
||
| # [START howto_task_group_inner_section_2] | ||
| with TaskGroup("inner_section_2", tooltip="Tasks for inner_section2") as inner_section_2: | ||
| task_2 = DummyOperator(task_id="task_2") | ||
| task_3 = DummyOperator(task_id="task_3") | ||
| task_4 = DummyOperator(task_id="task_4") | ||
|
|
||
| [task_2, task_3] >> task_4 | ||
| # [END howto_task_group_inner_section_2] | ||
|
|
||
| # [END howto_task_group_section_2] | ||
|
|
||
| end = DummyOperator(task_id='end') | ||
|
|
||
| start >> section_1 >> section_2 >> end | ||
| # [END howto_task_group] | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,8 @@ | |
| from abc import ABCMeta, abstractmethod | ||
| from datetime import datetime, timedelta | ||
| from typing import ( | ||
| Any, Callable, ClassVar, Dict, FrozenSet, Iterable, List, Optional, Sequence, Set, Tuple, Type, Union, | ||
| TYPE_CHECKING, Any, Callable, ClassVar, Dict, FrozenSet, Iterable, List, Optional, Sequence, Set, Tuple, | ||
| Type, Union, | ||
| ) | ||
|
|
||
| import attr | ||
|
|
@@ -58,6 +59,9 @@ | |
| from airflow.utils.trigger_rule import TriggerRule | ||
| from airflow.utils.weight_rule import WeightRule | ||
|
|
||
| if TYPE_CHECKING: | ||
| from airflow.utils.task_group import TaskGroup # pylint: disable=cyclic-import | ||
yuqian90 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ScheduleInterval = Union[str, timedelta, relativedelta] | ||
|
|
||
| TaskStateChangeCallback = Callable[[Context], None] | ||
|
|
@@ -360,9 +364,12 @@ def __init__( | |
| do_xcom_push: bool = True, | ||
| inlets: Optional[Any] = None, | ||
| outlets: Optional[Any] = None, | ||
| task_group: Optional["TaskGroup"] = None, | ||
| **kwargs | ||
| ): | ||
| from airflow.models.dag import DagContext | ||
| from airflow.utils.task_group import TaskGroupContext | ||
yuqian90 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| super().__init__() | ||
| if kwargs: | ||
| if not conf.getboolean('operators', 'ALLOW_ILLEGAL_ARGUMENTS'): | ||
|
|
@@ -382,6 +389,11 @@ def __init__( | |
| ) | ||
| validate_key(task_id) | ||
| self.task_id = task_id | ||
| self.label = task_id | ||
| task_group = task_group or TaskGroupContext.get_current_task_group(dag) | ||
| if task_group: | ||
| self.task_id = task_group.child_id(task_id) | ||
| task_group.add(self) | ||
| self.owner = owner | ||
| self.email = email | ||
| self.email_on_retry = email_on_retry | ||
|
|
@@ -609,7 +621,7 @@ def dag(self, dag: Any): | |
| elif self.task_id in dag.task_dict and dag.task_dict[self.task_id] is not self: | ||
| dag.add_task(self) | ||
|
|
||
| self._dag = dag # pylint: disable=attribute-defined-outside-init | ||
| self._dag = dag | ||
|
|
||
| def has_dag(self): | ||
| """ | ||
|
|
@@ -1120,21 +1132,25 @@ def roots(self) -> List["BaseOperator"]: | |
| """Required by TaskMixin""" | ||
| return [self] | ||
|
|
||
| @property | ||
| def leaves(self) -> List["BaseOperator"]: | ||
| """Required by TaskMixin""" | ||
| return [self] | ||
|
|
||
| def _set_relatives( | ||
| self, | ||
| task_or_task_list: Union[TaskMixin, Sequence[TaskMixin]], | ||
| upstream: bool = False, | ||
| ) -> None: | ||
| """Sets relatives for the task or task list.""" | ||
|
|
||
| if isinstance(task_or_task_list, Sequence): | ||
| task_like_object_list = task_or_task_list | ||
| else: | ||
| task_like_object_list = [task_or_task_list] | ||
| if not isinstance(task_or_task_list, Sequence): | ||
| task_or_task_list = [task_or_task_list] | ||
|
|
||
| task_list: List["BaseOperator"] = [] | ||
| for task_object in task_like_object_list: | ||
| task_list.extend(task_object.roots) | ||
| for task_object in task_or_task_list: | ||
| task_object.update_relative(self, not upstream) | ||
|
||
| relatives = task_object.leaves if upstream else task_object.roots | ||
| task_list.extend(relatives) | ||
|
|
||
| for task in task_list: | ||
| if not isinstance(task, BaseOperator): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,3 +43,4 @@ class DagAttributeTypes(str, Enum): | |
| SET = 'set' | ||
| TUPLE = 'tuple' | ||
| POD = 'k8s.V1Pod' | ||
| TASK_GROUP = 'taskgroup' | ||
Uh oh!
There was an error while loading. Please reload this page.