From e66aaa66a5bc231a8452b1927f1f1266332ba23e Mon Sep 17 00:00:00 2001 From: Martin Krizek Date: Mon, 24 Mar 2025 15:39:17 +0100 Subject: [PATCH] Improve performance of including tasks into the play (#84445) * Improve performance of including tasks into the play PlayIterator.add_tasks is used to insert tasks from an include into the play for particular host. It makes a copy of the current block including the tasks within the block and inserts the new tasks from the include into the copied block. But there is no need to make copies of tasks within the block, what we want is a "shallow" copy of the block. This PR changes that to copy the block excluding the tasks within. On a contrived playbook with 50 include_role tasks, each role has 1 task, running on 10 hosts the running time is reduced from ~55s to ~44s in my environment. ci_complete * Add changelog --- .../playiterator-add_tasks-optimize.yml | 2 ++ lib/ansible/executor/play_iterator.py | 18 ++++++------------ lib/ansible/playbook/block.py | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) create mode 100644 changelogs/fragments/playiterator-add_tasks-optimize.yml diff --git a/changelogs/fragments/playiterator-add_tasks-optimize.yml b/changelogs/fragments/playiterator-add_tasks-optimize.yml new file mode 100644 index 00000000000..a0b69242fe0 --- /dev/null +++ b/changelogs/fragments/playiterator-add_tasks-optimize.yml @@ -0,0 +1,2 @@ +bugfixes: + - Optimize the way tasks from within ``include_tasks``/``include_role`` are inserted into the play. diff --git a/lib/ansible/executor/play_iterator.py b/lib/ansible/executor/play_iterator.py index e512b64b840..54ed6ca3b1f 100644 --- a/lib/ansible/executor/play_iterator.py +++ b/lib/ansible/executor/play_iterator.py @@ -598,28 +598,22 @@ class PlayIterator: if state.tasks_child_state: state.tasks_child_state = self._insert_tasks_into_state(state.tasks_child_state, task_list) else: - target_block = state._blocks[state.cur_block].copy() - before = target_block.block[:state.cur_regular_task] - after = target_block.block[state.cur_regular_task:] - target_block.block = before + task_list + after + target_block = state._blocks[state.cur_block].copy(exclude_tasks=True) + target_block.block[state.cur_regular_task:state.cur_regular_task] = task_list state._blocks[state.cur_block] = target_block elif state.run_state == IteratingStates.RESCUE: if state.rescue_child_state: state.rescue_child_state = self._insert_tasks_into_state(state.rescue_child_state, task_list) else: - target_block = state._blocks[state.cur_block].copy() - before = target_block.rescue[:state.cur_rescue_task] - after = target_block.rescue[state.cur_rescue_task:] - target_block.rescue = before + task_list + after + target_block = state._blocks[state.cur_block].copy(exclude_tasks=True) + target_block.rescue[state.cur_rescue_task:state.cur_rescue_task] = task_list state._blocks[state.cur_block] = target_block elif state.run_state == IteratingStates.ALWAYS: if state.always_child_state: state.always_child_state = self._insert_tasks_into_state(state.always_child_state, task_list) else: - target_block = state._blocks[state.cur_block].copy() - before = target_block.always[:state.cur_always_task] - after = target_block.always[state.cur_always_task:] - target_block.always = before + task_list + after + target_block = state._blocks[state.cur_block].copy(exclude_tasks=True) + target_block.always[state.cur_always_task:state.cur_always_task] = task_list state._blocks[state.cur_block] = target_block elif state.run_state == IteratingStates.HANDLERS: state.handlers[state.cur_handlers_task:state.cur_handlers_task] = [h for b in task_list for h in b.block] diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py index f7dd8994e2e..464ff3879c5 100644 --- a/lib/ansible/playbook/block.py +++ b/lib/ansible/playbook/block.py @@ -177,7 +177,7 @@ class Block(Base, Conditional, CollectionSearch, Taggable, Notifiable, Delegatab def _dupe_task_list(task_list, new_block): new_task_list = [] for task in task_list: - new_task = task.copy(exclude_parent=True) + new_task = task.copy(exclude_parent=True, exclude_tasks=exclude_tasks) if task._parent: new_task._parent = task._parent.copy(exclude_tasks=True) if task._parent == new_block: