Merge branch 'main' of git.stroblme.de:Fluksio/app
Docs / docs (push) Successful in 21s
Playwright Tests / test-playwright (1, 2) (push) Failing after 15m39s
Playwright Tests / test-playwright (2, 2) (push) Successful in 10m17s
pre-commit / pre-commit (push) Failing after 2m28s
Test Backend / test-backend (push) Failing after 2m29s
Compose Smoke Test / test-compose (push) Successful in 30s
Playwright Tests / merge-reports (push) Successful in 5m36s
Docs / docs (push) Successful in 21s
Playwright Tests / test-playwright (1, 2) (push) Failing after 15m39s
Playwright Tests / test-playwright (2, 2) (push) Successful in 10m17s
pre-commit / pre-commit (push) Failing after 2m28s
Test Backend / test-backend (push) Failing after 2m29s
Compose Smoke Test / test-compose (push) Successful in 30s
Playwright Tests / merge-reports (push) Successful in 5m36s
The two sides both touched `submit_ready`'s readiness check, for unrelated reasons, so the conflict is textual rather than semantic and both changes stand: - `831a537` completes a node that is not ready instead of passing over it, so a producer that can never run stops stranding its consumers. - the audit branch has `_is_node_ready` return the values it read, so the node runs on them instead of asking state for the same keys again. Merged as: read once, keep the values whether or not the answer is yes, and take the not-ready branch from `831a537`. Its reasoning holds under the merge — by the time readiness is consulted, `in_degree` is zero and every in-wave producer has finished, so the answer cannot change later in the wave. Also fixes a fixture this branch added: the module-scoped row cleanup in `tests/conftest.py` assumed a schema, and `tests/flow` overrides `db` with a no-op because those tests need no database. It only showed when that directory ran on its own. 746 tests green, and each directory green alone. Engine throughput is unchanged by the merge (559 msg/s on the memory backend, against 639 before it and 262 at the start of the audit). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M6hPWS6YEbT1P8LxhhFb2T
This commit is contained in:
@@ -1352,12 +1352,30 @@ class Pipeline:
|
||||
continue
|
||||
ready_inputs: dict[str, Any] | None = None
|
||||
if check_ready:
|
||||
# The values are kept whether or not the answer is yes:
|
||||
# a node that may run reads them below instead of
|
||||
# asking state for the same keys again.
|
||||
ready, ready_inputs = self._is_node_ready(n, state)
|
||||
if not ready:
|
||||
if n.synchronous:
|
||||
# Not ready now; a later trigger may make it
|
||||
# ready.
|
||||
skipped.add(n)
|
||||
# Completed, not merely passed over: a later trigger
|
||||
# may still make it ready, but not running is not
|
||||
# the same as blocking. Whatever it last published
|
||||
# is in state, and a consumer reading that alongside
|
||||
# something this wave *did* publish has every right
|
||||
# to run on the pair.
|
||||
#
|
||||
# Passing over it held that consumer for the whole
|
||||
# wave, and a node that can never be ready — an
|
||||
# input nothing has ever published — took its
|
||||
# consumers out for good. On this house
|
||||
# `plugs.pump_run` waits on a watering pulse that
|
||||
# only exists at 02:00, and it sits upstream of
|
||||
# `dmx.switches`: every boiler, plug and appliance
|
||||
# command reached its own message and stopped there,
|
||||
# reaching the DMX universe only in the occasional
|
||||
# wave the pump node happened not to be part of.
|
||||
complete(n)
|
||||
progressed = True
|
||||
continue
|
||||
if replay and entry_id and self._already_done(entry_id, n):
|
||||
# Its side effect happened on an earlier delivery; its
|
||||
@@ -1379,17 +1397,23 @@ class Pipeline:
|
||||
|
||||
for n in completed:
|
||||
result = node_futures.pop(n).result()
|
||||
# A node returning nothing (rate limiting, an error) stops
|
||||
# propagation along its branch.
|
||||
if result is not None:
|
||||
# Before the decrement: a consumer freed by this node
|
||||
# is judged on what it just published.
|
||||
if fresh is not None:
|
||||
fresh.update(result)
|
||||
for consumer in edges[n]:
|
||||
if consumer in target_nodes:
|
||||
in_degree[consumer] -= 1
|
||||
submit_ready(executor)
|
||||
# Before the decrement: a consumer freed by this node is
|
||||
# judged on what it just published.
|
||||
if result is not None and fresh is not None:
|
||||
fresh.update(result)
|
||||
# Decremented whatever it returned. A node that published
|
||||
# nothing — rate limited, unchanged, or failed — has not
|
||||
# *blocked* its consumers; it has merely given them nothing
|
||||
# to read, and `untouched` above is the accurate test of
|
||||
# that. Holding the count instead made a quiet producer
|
||||
# veto a noisy sibling: `dmx.switches` reads both boilers
|
||||
# through report-by-exception nodes, so the kitchen one
|
||||
# staying silent — which is almost always — kept the main
|
||||
# boiler's command from ever reaching the DMX universe.
|
||||
for consumer in edges[n]:
|
||||
if consumer in target_nodes:
|
||||
in_degree[consumer] -= 1
|
||||
submit_ready(executor)
|
||||
|
||||
if self._node_pool is not None:
|
||||
# The execution service owns a long-lived pool; building one per
|
||||
|
||||
Reference in New Issue
Block a user