child graphs can interrupt/resume
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from wf_core.conditions import eval_condition
|
||||
from wf_core.errors import WorkflowExecutionError
|
||||
from wf_core.models.steps import ConditionNode, InterruptNode
|
||||
from wf_core.run_state import FrameStatus, RunState, RunStatus, StepExecutionResult
|
||||
from wf_core.run_state import (
|
||||
ROOT_SCOPE_ID,
|
||||
ExecutionFrame,
|
||||
FrameStatus,
|
||||
InterruptRoute,
|
||||
RunState,
|
||||
RunStatus,
|
||||
StepExecutionResult,
|
||||
)
|
||||
from wf_core.runtime.lineage import scope_input_for_frame
|
||||
from wf_core.runtime.ops.flow import append_trace
|
||||
from wf_core.runtime.ops.frames import frame_context_values
|
||||
@@ -44,12 +53,32 @@ def handle_interrupt_step(
|
||||
step: InterruptNode,
|
||||
) -> RunState:
|
||||
frame = run.current_frame()
|
||||
public_frame = frame
|
||||
route = None
|
||||
if frame.scope_id != ROOT_SCOPE_ID:
|
||||
public_frame = _owning_subgraph_frame(run, frame)
|
||||
scope = run.scopes.get(frame.scope_id)
|
||||
if scope is None or scope.workflow_ref is None:
|
||||
raise WorkflowExecutionError(
|
||||
f"child interrupt frame {frame.id!r} has no workflow scope"
|
||||
)
|
||||
route = InterruptRoute(
|
||||
frame_id=frame.id,
|
||||
node_id=frame.node_id,
|
||||
scope_id=frame.scope_id,
|
||||
lineage_id=frame.lineage_id,
|
||||
parent_frame_id=public_frame.id,
|
||||
workflow_ref=scope.workflow_ref,
|
||||
)
|
||||
interrupt_request = build_interrupt_request(
|
||||
step,
|
||||
frame_id=frame.id,
|
||||
state=run.state,
|
||||
workflow_input=run.workflow_input,
|
||||
state=state_view_for_frame(run, frame),
|
||||
workflow_input=scope_input_for_frame(run, frame),
|
||||
context=frame_context_values(frame),
|
||||
public_frame_id=public_frame.id,
|
||||
public_node_id=public_frame.node_id,
|
||||
route=route,
|
||||
)
|
||||
run.interrupt = interrupt_request
|
||||
run.status = RunStatus.INTERRUPTED
|
||||
@@ -66,3 +95,21 @@ def handle_interrupt_step(
|
||||
state_changes={},
|
||||
)
|
||||
return run
|
||||
|
||||
|
||||
def _owning_subgraph_frame(run: RunState, frame: ExecutionFrame) -> ExecutionFrame:
|
||||
"""Return the graph-boundary frame that owns one child-scope interrupt."""
|
||||
cursor = frame
|
||||
while cursor.parent_frame_id is not None:
|
||||
parent = run.frames.get(cursor.parent_frame_id)
|
||||
if parent is None:
|
||||
raise WorkflowExecutionError(
|
||||
f"child interrupt frame {frame.id!r} references missing parent "
|
||||
f"{cursor.parent_frame_id!r}"
|
||||
)
|
||||
if parent.scope_id != frame.scope_id:
|
||||
return parent
|
||||
cursor = parent
|
||||
raise WorkflowExecutionError(
|
||||
f"child interrupt frame {frame.id!r} has no parent subgraph"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user