mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 15:09:46 +08:00
refactor: unify workflow runtime boundary
This commit is contained in:
+7
-1
@@ -145,7 +145,13 @@ def configure_plugin_system_services():
|
||||
configure_module_runtime(lambda: ModuleManager())
|
||||
from app.application.site.query import SiteQueryService, configure_site_query_service
|
||||
from app.application.site.health import SiteHealthService, configure_site_health_service
|
||||
from app.application.workflow import WorkflowQueryService, configure_workflow_query
|
||||
from app.application.workflow import (
|
||||
WorkflowQueryService,
|
||||
configure_workflow_query,
|
||||
configure_workflow_runtime,
|
||||
)
|
||||
from app.workflow import WorkFlowManager
|
||||
configure_workflow_runtime(lambda: WorkFlowManager())
|
||||
from app.application.agentdata import configure_agent_data_ports
|
||||
from app.db.oper.agentchat import AgentChatOper
|
||||
from app.db.oper.downloadfailure import DownloadFailureOper
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@
|
||||
"workflow_to_db": []
|
||||
},
|
||||
"edge_count": 6544,
|
||||
"edge_sha256": "44812359c634235d327fdc499bc0ccf93e24923fba24bed4a29fc14adc26bf84",
|
||||
"edge_sha256": "562471ed16680ca403b6cdb7661b20b1200c53b75da5e162efe4e7400cde174b",
|
||||
"edges": [
|
||||
"app -> app.runtime",
|
||||
"app -> app.runtime.compat",
|
||||
@@ -1637,7 +1637,6 @@
|
||||
"app.api.dependencies.workflow -> app.startup",
|
||||
"app.api.dependencies.workflow -> app.startup.composition",
|
||||
"app.api.dependencies.workflow -> app.startup.composition.context",
|
||||
"app.api.dependencies.workflow -> app.workflow",
|
||||
"app.api.deps -> app.api",
|
||||
"app.api.deps -> app.api.dependencies",
|
||||
"app.api.deps -> app.api.dependencies.agent",
|
||||
@@ -2417,7 +2416,6 @@
|
||||
"app.api.endpoints.workflow -> app.schemas.response",
|
||||
"app.api.endpoints.workflow -> app.schemas.types",
|
||||
"app.api.endpoints.workflow -> app.schemas.workflow",
|
||||
"app.api.endpoints.workflow -> app.workflow",
|
||||
"app.api.response -> app.schemas",
|
||||
"app.api.response -> app.schemas.common",
|
||||
"app.api.response -> app.schemas.response",
|
||||
@@ -3480,6 +3478,7 @@
|
||||
"app.chain.workflow -> app.application",
|
||||
"app.chain.workflow -> app.application.chain",
|
||||
"app.chain.workflow -> app.application.chain.data",
|
||||
"app.chain.workflow -> app.application.workflow",
|
||||
"app.chain.workflow -> app.chain",
|
||||
"app.chain.workflow -> app.runtime",
|
||||
"app.chain.workflow -> app.runtime.config",
|
||||
@@ -3488,7 +3487,6 @@
|
||||
"app.chain.workflow -> app.schemas",
|
||||
"app.chain.workflow -> app.schemas.types",
|
||||
"app.chain.workflow -> app.schemas.workflow",
|
||||
"app.chain.workflow -> app.workflow",
|
||||
"app.cli -> app.application",
|
||||
"app.cli -> app.application.backup",
|
||||
"app.cli -> app.doctor",
|
||||
@@ -6336,6 +6334,8 @@
|
||||
"app.startup.initializers.scheduler -> app.scheduler",
|
||||
"app.startup.initializers.transfer -> app.chain",
|
||||
"app.startup.initializers.transfer -> app.chain.transfer",
|
||||
"app.startup.initializers.workflow -> app.application",
|
||||
"app.startup.initializers.workflow -> app.application.workflow",
|
||||
"app.startup.initializers.workflow -> app.workflow",
|
||||
"app.startup.lifecycle -> app.adapters",
|
||||
"app.startup.lifecycle -> app.adapters.external",
|
||||
|
||||
@@ -926,6 +926,20 @@ def test_runtime_consumers_use_command_application_facade():
|
||||
assert violations == {}
|
||||
|
||||
|
||||
def test_runtime_consumers_use_workflow_application_facade():
|
||||
"""WorkFlowManager concrete 实现只允许 startup 组合根直接依赖。"""
|
||||
allowed = {"app.startup.initializers.workflow"}
|
||||
violations = {
|
||||
module_name: dependencies & {"app.workflow"}
|
||||
for module_name, dependencies in _build_module_graph().items()
|
||||
if not module_name.startswith("app.workflow")
|
||||
and module_name not in allowed
|
||||
and "app.workflow" in dependencies
|
||||
}
|
||||
|
||||
assert violations == {}
|
||||
|
||||
|
||||
def test_modules_read_deployment_settings_through_runtime_port():
|
||||
"""宿主 Module 不得绕过 runtime 配置端口直接依赖 Settings 实例。"""
|
||||
violations: list[str] = []
|
||||
|
||||
@@ -142,7 +142,7 @@ def test_workflow_executor_preserves_trigger_context(monkeypatch):
|
||||
[],
|
||||
results={"A": run_action},
|
||||
)
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(
|
||||
workflow_module.global_vars,
|
||||
"workflow_resume",
|
||||
@@ -189,7 +189,7 @@ def test_workflow_executor_resumes_downstream_nodes(monkeypatch):
|
||||
context=_encoded_context(ActionContext()),
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -214,7 +214,7 @@ def test_workflow_executor_restores_structured_context(monkeypatch):
|
||||
},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -232,7 +232,7 @@ def test_workflow_executor_reports_incremental_progress(monkeypatch):
|
||||
progresses = []
|
||||
fake_manager = _FakeWorkflowManager(calls)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -272,7 +272,7 @@ def test_workflow_executor_skips_false_condition_branch(monkeypatch):
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -325,7 +325,7 @@ def test_workflow_executor_all_success_join_waits_parallel_branches(monkeypatch)
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -367,7 +367,7 @@ def test_workflow_executor_any_success_join_runs_after_available_branch(monkeypa
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -399,7 +399,7 @@ def test_workflow_executor_all_done_join_can_continue_after_failure(monkeypatch)
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -438,7 +438,7 @@ def test_workflow_executor_exclusive_branch_uses_first_matching_flow(monkeypatch
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -475,7 +475,7 @@ def test_workflow_executor_passes_declared_inputs(monkeypatch):
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -516,7 +516,7 @@ def test_workflow_executor_uses_contract_inputs(monkeypatch):
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -543,7 +543,7 @@ def test_workflow_executor_persists_structured_state(monkeypatch):
|
||||
}
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -576,7 +576,7 @@ def test_workflow_executor_restores_outputs_from_execution_state(monkeypatch):
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -603,7 +603,7 @@ def test_workflow_executor_keeps_execution_state_dict_for_non_json_leaf(monkeypa
|
||||
}
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -634,7 +634,7 @@ def test_workflow_chain_process_serializes_circular_context(monkeypatch):
|
||||
)
|
||||
fake_oper = _FakeWorkflowOper(workflow)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "WorkflowOper", lambda: fake_oper)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
@@ -683,7 +683,7 @@ def test_workflow_executor_concurrency_key_serializes_parallel_nodes(monkeypatch
|
||||
execution_config={"max_workers": 2},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -721,7 +721,7 @@ def test_workflow_executor_filter_action_replaces_artifact_outputs(monkeypatch):
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -772,7 +772,7 @@ def test_workflow_executor_filter_action_replaces_with_empty_outputs(monkeypatch
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: False)
|
||||
|
||||
@@ -789,7 +789,7 @@ def test_workflow_executor_stop_is_not_success(monkeypatch):
|
||||
calls = []
|
||||
fake_manager = _FakeWorkflowManager(calls)
|
||||
|
||||
monkeypatch.setattr(workflow_module, "WorkFlowManager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module, "get_workflow_manager", lambda: fake_manager)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "workflow_resume", lambda workflow_id: None)
|
||||
monkeypatch.setattr(workflow_module.global_vars, "is_workflow_stopped", lambda workflow_id: True)
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
"""工作流运行时 Application Facade 回归。"""
|
||||
|
||||
import pytest
|
||||
|
||||
from app.application import workflow as workflow_application
|
||||
|
||||
|
||||
def test_workflow_runtime_facade_preserves_registered_identity(monkeypatch) -> None:
|
||||
"""Application Facade 必须返回组合根登记的同一个运行时对象。"""
|
||||
runtime = object()
|
||||
monkeypatch.setattr(
|
||||
workflow_application,
|
||||
"_workflow_runtime_provider",
|
||||
lambda: runtime,
|
||||
)
|
||||
|
||||
assert workflow_application.get_workflow_manager() is runtime
|
||||
|
||||
|
||||
def test_workflow_runtime_facade_fails_before_composition(monkeypatch) -> None:
|
||||
"""未装配时不得隐式创建第二个 WorkFlowManager Singleton。"""
|
||||
monkeypatch.setattr(
|
||||
workflow_application,
|
||||
"_workflow_runtime_provider",
|
||||
workflow_application._unconfigured_workflow_runtime,
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="工作流运行时尚未由启动组合根装配"):
|
||||
workflow_application.get_workflow_manager()
|
||||
Reference in New Issue
Block a user