Stop and start a flow without rebuilding anything
A stopped flow's nodes are built like any other flow's — being stopped means having no subscriptions, schedules or webhooks, not being absent — so a toggle only ever needed the lifecycle call and the gate that goes with it. It was doing a whole-pipeline rebuild instead, which on a populated installation is every node in every flow reconnecting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01StpRc2C6au1WJ1EUU7fsfu
This commit is contained in:
@@ -297,3 +297,38 @@ def test_a_deleted_flow_leaves_its_consumers_reporting_a_missing_input(
|
||||
assert engine.pipeline.get_node_by_id("a.meter") is None
|
||||
|
||||
asyncio.run(asyncio.wait_for(scenario(), timeout=10))
|
||||
|
||||
|
||||
def test_stopping_one_flow_does_not_touch_the_others(
|
||||
tmp_path: Path, lifecycle: list[str]
|
||||
):
|
||||
"""A toggle is a lifecycle call, not a rebuild.
|
||||
|
||||
A stopped flow's nodes are still built — being stopped means having no
|
||||
subscriptions, not being absent — so nothing is compiled and no other
|
||||
flow's node is asked to reconnect. That is where the seconds went.
|
||||
"""
|
||||
store = FlowStore(tmp_path / "flows")
|
||||
for name in ("a", "b"):
|
||||
store.write_flow(FlowDef(name=name, nodes=[NodeDef(id="io", type="lifecycle")]))
|
||||
engine = FlowController(store)
|
||||
|
||||
async def scenario() -> None:
|
||||
await engine.reload()
|
||||
before = {name: engine.loaded[name].node for name in ("a.io", "b.io")}
|
||||
lifecycle.clear()
|
||||
|
||||
await engine.set_enabled("a", False)
|
||||
|
||||
assert lifecycle == ["stop a.io"]
|
||||
# Still built, still the same objects: only the lifecycle changed.
|
||||
assert {name: engine.loaded[name].node for name in ("a.io", "b.io")} == before
|
||||
assert engine.disabled == {"a"}
|
||||
|
||||
lifecycle.clear()
|
||||
await engine.set_enabled("a", True)
|
||||
|
||||
assert lifecycle == ["start a.io"]
|
||||
assert {name: engine.loaded[name].node for name in ("a.io", "b.io")} == before
|
||||
|
||||
asyncio.run(asyncio.wait_for(scenario(), timeout=10))
|
||||
|
||||
Reference in New Issue
Block a user