refactor(api): continue decoupling dify_graph from API concerns (#33580)

Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: WH-2099 <wh2099@pm.me>
This commit is contained in:
-LAN-
2026-03-25 20:32:24 +08:00
committed by GitHub
parent b7b9b003c9
commit 56593f20b0
487 changed files with 17999 additions and 9186 deletions

View File

@ -28,6 +28,7 @@ from dify_graph.graph_events import (
NodeRunStartedEvent,
NodeRunStreamChunkEvent,
NodeRunSucceededEvent,
NodeRunVariableUpdatedEvent,
)
from dify_graph.model_runtime.entities.llm_entities import LLMUsage
from dify_graph.runtime import GraphRuntimeState
@ -93,6 +94,10 @@ class EventHandler:
Args:
event: The event to handle
"""
if isinstance(event, NodeRunVariableUpdatedEvent):
self._dispatch(event)
return
# Events in loops or iterations are always collected
if event.in_loop_id or event.in_iteration_id:
self._event_collector.collect(event)
@ -153,6 +158,17 @@ class EventHandler:
for stream_event in streaming_events:
self._event_collector.collect(stream_event)
@_dispatch.register
def _(self, event: NodeRunVariableUpdatedEvent) -> None:
"""
Apply a node-requested variable mutation before downstream observers run.
The event is collected like other node events so parent/container engines can
forward the updated payload to outer layers, including persistence listeners.
"""
self._graph_runtime_state.variable_pool.add(event.variable.selector, event.variable)
self._event_collector.collect(event)
@_dispatch.register
def _(self, event: NodeRunSucceededEvent) -> None:
"""

View File

@ -9,10 +9,9 @@ from __future__ import annotations
import logging
import queue
from collections.abc import Generator, Mapping
from collections.abc import Generator
from typing import TYPE_CHECKING, cast, final
from dify_graph.context import capture_current_context
from dify_graph.entities.workflow_start_reason import WorkflowStartReason
from dify_graph.enums import NodeExecutionType
from dify_graph.graph import Graph
@ -26,7 +25,7 @@ from dify_graph.graph_events import (
GraphRunStartedEvent,
GraphRunSucceededEvent,
)
from dify_graph.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper
from dify_graph.runtime import GraphRuntimeState, ReadOnlyGraphRuntimeStateWrapper, VariablePool
from dify_graph.runtime.graph_runtime_state import ChildGraphEngineBuilderProtocol
if TYPE_CHECKING: # pragma: no cover - used only for static analysis
@ -86,6 +85,7 @@ class GraphEngine:
self._graph_runtime_state.configure(graph=cast("GraphProtocol", graph))
self._command_channel = command_channel
self._config = config
self._layers: list[GraphEngineLayer] = []
self._child_engine_builder = child_engine_builder
if child_engine_builder is not None:
self._graph_runtime_state.bind_child_engine_builder(child_engine_builder)
@ -149,21 +149,14 @@ class GraphEngine:
update_variables_handler = UpdateVariablesCommandHandler(self._graph_runtime_state.variable_pool)
self._command_processor.register_handler(UpdateVariablesCommand, update_variables_handler)
# === Extensibility ===
# Layers allow plugins to extend engine functionality
self._layers: list[GraphEngineLayer] = []
# === Worker Pool Setup ===
# Capture execution context for worker threads
execution_context = capture_current_context()
# Create worker pool for parallel node execution
self._worker_pool = WorkerPool(
ready_queue=self._ready_queue,
event_queue=self._event_queue,
graph=self._graph,
layers=self._layers,
execution_context=execution_context,
execution_context=self._graph_runtime_state.execution_context,
config=self._config,
)
@ -220,23 +213,23 @@ class GraphEngine:
self._bind_layer_context(layer)
return self
def request_abort(self, reason: str | None = None) -> None:
"""Queue an abort command for this engine."""
self._command_channel.send_command(AbortCommand(reason=reason or "User requested abort"))
def create_child_engine(
self,
*,
workflow_id: str,
graph_init_params: GraphInitParams,
graph_runtime_state: GraphRuntimeState,
graph_config: dict[str, object] | Mapping[str, object],
root_node_id: str,
layers: list[GraphEngineLayer] | tuple[GraphEngineLayer, ...] = (),
variable_pool: VariablePool | None = None,
) -> GraphEngine:
return self._graph_runtime_state.create_child_engine(
workflow_id=workflow_id,
graph_init_params=graph_init_params,
graph_runtime_state=graph_runtime_state,
graph_config=graph_config,
root_node_id=root_node_id,
layers=layers,
variable_pool=variable_pool,
)
def run(self) -> Generator[GraphEngineEvent, None, None]:

View File

@ -9,19 +9,18 @@ import queue
import threading
import time
from collections.abc import Sequence
from datetime import datetime
from contextlib import AbstractContextManager
from datetime import UTC, datetime
from typing import TYPE_CHECKING, final
from typing_extensions import override
from dify_graph.context import IExecutionContext
from dify_graph.enums import WorkflowNodeExecutionStatus
from dify_graph.graph import Graph
from dify_graph.graph_engine.layers.base import GraphEngineLayer
from dify_graph.graph_events import GraphNodeEventBase, NodeRunFailedEvent, NodeRunStartedEvent, is_node_result_event
from dify_graph.node_events import NodeRunResult
from dify_graph.nodes.base.node import Node
from libs.datetime_utils import naive_utc_now
from .ready_queue import ReadyQueue
@ -46,7 +45,7 @@ class Worker(threading.Thread):
graph: Graph,
layers: Sequence[GraphEngineLayer],
worker_id: int = 0,
execution_context: IExecutionContext | None = None,
execution_context: AbstractContextManager[object] | None = None,
) -> None:
"""
Initialize worker thread.
@ -187,7 +186,7 @@ class Worker(threading.Thread):
self, node: Node, error: Exception, *, started_at: datetime | None = None
) -> NodeRunFailedEvent:
"""Build a failed event when worker-level execution aborts before a node emits its own result event."""
failure_time = naive_utc_now()
failure_time = datetime.now(UTC).replace(tzinfo=None)
error_message = str(error)
return NodeRunFailedEvent(
id=node.execution_id,

View File

@ -8,9 +8,9 @@ DynamicScaler, and WorkerFactory into a single class.
import logging
import queue
import threading
from contextlib import AbstractContextManager
from typing import final
from dify_graph.context import IExecutionContext
from dify_graph.graph import Graph
from dify_graph.graph_events import GraphNodeEventBase
@ -38,7 +38,7 @@ class WorkerPool:
graph: Graph,
layers: list[GraphEngineLayer],
config: GraphEngineConfig,
execution_context: IExecutionContext | None = None,
execution_context: AbstractContextManager[object] | None = None,
) -> None:
"""
Initialize the simple worker pool.