Fix finally block executing twice on successful workflow runs (#4659)

This commit is contained in:
Marc Kelechava
2026-02-07 00:35:13 -08:00
committed by GitHub
parent ce372cfdb8
commit cb7225c6e6

View File

@@ -1078,6 +1078,10 @@ class WorkflowService:
else:
blocks = top_level_blocks
# Exclude the finally block from normal traversal — it runs separately via _execute_finally_block_if_configured
finally_block_label = workflow.workflow_definition.finally_block_label
if finally_block_label:
blocks = self._strip_finally_block_references(blocks, finally_block_label)
if not blocks:
raise SkyvernException(f"No blocks found for the given block labels: {block_labels}")
@@ -1187,10 +1191,13 @@ class WorkflowService:
is_script_run: bool,
blocks_to_update: set[str],
) -> tuple[WorkflowRun, set[str]]:
finally_block_label = workflow.workflow_definition.finally_block_label
dag_blocks = workflow.workflow_definition.blocks
if finally_block_label:
dag_blocks = self._strip_finally_block_references(dag_blocks, finally_block_label)
try:
start_label, label_to_block, default_next_map = self._build_workflow_graph(
workflow.workflow_definition.blocks
)
start_label, label_to_block, default_next_map = self._build_workflow_graph(dag_blocks)
except InvalidWorkflowDefinition as exc:
LOG.error("Workflow graph validation failed", error=str(exc), workflow_id=workflow.workflow_id)
workflow_run = await self.mark_workflow_run_as_failed(
@@ -1628,6 +1635,34 @@ class WorkflowService:
error=str(e),
)
@staticmethod
def _strip_finally_block_references(
blocks: list[BlockTypeVar],
finally_block_label: str,
) -> list[BlockTypeVar]:
"""Remove the finally block and nullify any edges that point to it.
This prevents _build_workflow_graph from raising InvalidWorkflowDefinition
when a block's next_block_label references the (now-excluded) finally block.
"""
result: list[BlockTypeVar] = []
for block in blocks:
if block.label == finally_block_label:
continue
if isinstance(block, ConditionalBlock):
patched_branches = [
branch.model_copy(update={"next_block_label": None})
if branch.next_block_label == finally_block_label
else branch
for branch in block.branch_conditions
]
if patched_branches != block.branch_conditions:
block = block.model_copy(update={"branch_conditions": patched_branches})
elif block.next_block_label == finally_block_label:
block = block.model_copy(update={"next_block_label": None})
result.append(block)
return result
def _build_workflow_graph(
self,
blocks: list[BlockTypeVar],