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:
@@ -426,9 +426,48 @@ class FlowController:
|
||||
entry.last_error_ts = None
|
||||
|
||||
async def set_enabled(self, flow: str, enabled: bool) -> None:
|
||||
"""Stop or start one flow. Rebuilding is what applies it."""
|
||||
"""Stop or start one flow, without building anything.
|
||||
|
||||
Its nodes are built whether or not it runs — being stopped means
|
||||
having no subscriptions, schedules or webhooks, not being absent — so
|
||||
all this has to do is the lifecycle call and the gate that goes with
|
||||
it. Nothing is compiled and no other flow is touched.
|
||||
"""
|
||||
await run_in_threadpool(self.store.write_enabled, flow, enabled)
|
||||
await self.reload()
|
||||
if self.pipeline is None:
|
||||
# Nothing built yet, so there are no nodes to start or stop.
|
||||
await self.reload()
|
||||
return
|
||||
|
||||
await self._acquire(FLOW_REBUILD_WAIT)
|
||||
try:
|
||||
if enabled:
|
||||
# The gate first: a subscription that fires the instant it
|
||||
# starts must not be turned away by a flag on its way out.
|
||||
self.disabled = self.disabled - {flow}
|
||||
self.pipeline.set_disabled(self.disabled)
|
||||
# Lifts any quarantine, which is what a rebuild used to do by
|
||||
# throwing the whole supervisor away.
|
||||
await self.supervisor.cancel_flow(flow)
|
||||
await self._activate(flow)
|
||||
else:
|
||||
self.disabled = self.disabled | {flow}
|
||||
self.pipeline.set_disabled(self.disabled)
|
||||
await self._teardown(flow)
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
self._publish(
|
||||
{
|
||||
"type": "pipeline_rebuilt",
|
||||
"issues": [issue.model_dump() for issue in self.issues],
|
||||
"nodes": [status.model_dump() for status in self.node_statuses()],
|
||||
# Every flow's, not this one's: the canvas replaces its paused
|
||||
# set from this, so a narrowed list would clear the markers of
|
||||
# flows this never touched.
|
||||
"paused": self.paused_flows(),
|
||||
}
|
||||
)
|
||||
|
||||
async def _acquire(self, wait: float | None) -> None:
|
||||
"""Take the rebuild lock, or say the engine is busy.
|
||||
|
||||
Reference in New Issue
Block a user