From af4f13f403ad4186f2234eddf3e98000a1638e5d Mon Sep 17 00:00:00 2001 From: OpenStack Release Bot Date: Fri, 5 Sep 2025 12:26:38 +0000 Subject: [PATCH 1/4] Update .gitreview for stable/2025.2 Change-Id: I6164bbc403aed9a815364bfc9da09308229f3543 Signed-off-by: OpenStack Release Bot Generated-By: openstack/project-config:roles/copy-release-tools-scripts/files/release-tools/functions --- .gitreview | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitreview b/.gitreview index a5276187e..60c676f74 100644 --- a/.gitreview +++ b/.gitreview @@ -2,3 +2,4 @@ host=review.opendev.org port=29418 project=openstack/taskflow.git +defaultbranch=stable/2025.2 From 9b186ac8b827532af2419d1560a5644ce0da31ad Mon Sep 17 00:00:00 2001 From: OpenStack Release Bot Date: Fri, 5 Sep 2025 12:26:40 +0000 Subject: [PATCH 2/4] Update TOX_CONSTRAINTS_FILE for stable/2025.2 Update the URL to the upper-constraints file to point to the redirect rule on releases.openstack.org so that anyone working on this branch will switch to the correct upper-constraints list automatically when the requirements repository branches. Until the requirements repository has as stable/2025.2 branch, tests will continue to use the upper-constraints list on master. Change-Id: I1a0dce6f3994e2b998c2846b7b7b0257fde87edf Signed-off-by: OpenStack Release Bot Generated-By: openstack/project-config:roles/copy-release-tools-scripts/files/release-tools/functions --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 50b4c85b6..75ce1b2a0 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ envlist = cover,docs,pep8,py3,pylint,update-states # We need to install a bit more than just `test' because those drivers have # custom tests that we always run deps = - -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt commands = From fdbbdbca4d9b285422cec955196656f1257c7f0b Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Mon, 31 Aug 2026 20:30:50 +0900 Subject: [PATCH 3/4] stable-only: Pin setuptools zake requires pkg_resources which was removed in recent setuptools. Change-Id: I0677faaed7a8f5ac65c95bdf896a63cf5e82e05e Signed-off-by: Takashi Kajinami --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 75ce1b2a0..6527e064a 100644 --- a/tox.ini +++ b/tox.ini @@ -9,6 +9,8 @@ deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/2025.2} -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt + # we need pkg_resources because of zake + setuptools<82 commands = stestr run {posargs} From ffe5977e404439570e0630e09cb6fcb03b71f92c Mon Sep 17 00:00:00 2001 From: Gregory Thiemonge Date: Wed, 28 Jan 2026 13:31:33 +0100 Subject: [PATCH 4/4] Avoid iterating over the same atoms in a graph When iterating over a "diamond" graph, some atoms may be processed multiple times. Depending on the size of the graph, it has a huge impact on the complexity of the algorithm. The patch ensures that each node is processed only once. Closes-Bug: #2139228 Closes-Bug: #2086453 Change-Id: Iced8a1fd02ef5766f4017bb1b6c6d48b4c061b5c Signed-off-by: Gregory Thiemonge (cherry picked from commit 6fc3a9b0f1868e3a6092007bb0fd8e79df6f5d95) --- taskflow/engines/action_engine/traversal.py | 10 ++++++++++ taskflow/tests/unit/test_engines.py | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/taskflow/engines/action_engine/traversal.py b/taskflow/engines/action_engine/traversal.py index abd14db53..7885d0d36 100644 --- a/taskflow/engines/action_engine/traversal.py +++ b/taskflow/engines/action_engine/traversal.py @@ -60,8 +60,13 @@ def breadth_first_iterate(execution_graph, starting_node, direction, through_flows=through_flows, through_retries=through_retries, through_tasks=through_tasks) q = collections.deque(initial_nodes_iter) + visited_nodes = set() while q: node = q.popleft() + if node in visited_nodes: + continue + visited_nodes.add(node) + node_attrs = execution_graph.nodes[node] if not node_attrs.get('noop'): yield node @@ -88,8 +93,13 @@ def depth_first_iterate(execution_graph, starting_node, direction, through_flows=through_flows, through_retries=through_retries, through_tasks=through_tasks) stack = list(initial_nodes_iter) + visited_nodes = set() while stack: node = stack.pop() + if node in visited_nodes: + continue + visited_nodes.add(node) + node_attrs = execution_graph.nodes[node] if not node_attrs.get('noop'): yield node diff --git a/taskflow/tests/unit/test_engines.py b/taskflow/tests/unit/test_engines.py index cd60c970e..215c2cfb0 100644 --- a/taskflow/tests/unit/test_engines.py +++ b/taskflow/tests/unit/test_engines.py @@ -632,6 +632,20 @@ def test_sequential_flow_two_tasks_with_resumption(self): self.assertEqual({'x1': 17, 'x2': 5}, engine.storage.fetch_all()) + # Reproducer for #2139228 and #2086453 + def test_many_unordered_flows_in_linear_flow(self): + flow = lf.Flow("root") + for i in range(10): + sf = uf.Flow(f'subflow {i}') + for j in range(10): + sf.add(utils.ProgressingTask(name=f"task {i}:{j}")) + flow.add(sf) + + engine = self._make_engine(flow) + with utils.CaptureListener(engine, capture_flow=False) as capturer: + engine.run() + self.assertIn("task 9:9.t SUCCESS(5)", capturer.values) + class EngineLinearAndUnorderedExceptionsTest(utils.EngineTestBase):