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
This commit is contained in:
Martin Krizek
2025-03-24 09:39:17 -05:00
committed by GitHub
parent 5280850130
commit e66aaa66a5
3 changed files with 9 additions and 13 deletions
@@ -0,0 +1,2 @@
bugfixes:
- Optimize the way tasks from within ``include_tasks``/``include_role`` are inserted into the play.
+6 -12
View File
@@ -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]
+1 -1
View File
@@ -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: