fix: two lane fixtures described a container that cannot exist (4295)
CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 3s
CI / frontend-build (push) Successful in 21s
CI / backend-lint-and-test (push) Successful in 32s
Build images / sign-extension (push) Successful in 3s
Build images / build-agent (push) Successful in 5s
Build images / build-web (push) Successful in 5s
CI / integration (push) Successful in 2m16s
Build images / smoke-web (push) Successful in 41s
Build images / promote (push) Skipped
CI / lint (push) Successful in 2s
CI / extension-version (push) Successful in 3s
CI / frontend-build (push) Successful in 21s
CI / backend-lint-and-test (push) Successful in 32s
Build images / sign-extension (push) Successful in 3s
Build images / build-agent (push) Successful in 5s
Build images / build-web (push) Successful in 5s
CI / integration (push) Successful in 2m16s
Build images / smoke-web (push) Successful in 41s
Build images / promote (push) Skipped
`pools={"host-a": 0}` — a celery replica running an empty pool. billiard will
not run one, and `gen_supervisord` starts every lane at one process for
exactly that reason, so no container has ever looked like this.
It passed for as long as the code agreed with it. The floor landed, the
reconcile's target for a zero-slot lane became one, and the fixture's
impossible zero read as a real difference: `changed: ['ml']` on a settled
lane, and run 7346 red on the commit that fixed the live bug.
Both now say one, which is what ml actually runs. The two tests the fix added
that asserted the same properties from the other side are gone with them —
one assertion per fact, in the test that already named it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
@@ -273,9 +273,14 @@ def test_one_lane_failing_does_not_stop_the_others(monkeypatch):
|
||||
def test_a_lane_disabled_in_settings_but_still_consuming_is_stopped(monkeypatch):
|
||||
"""The case that made `consuming` necessary: a lane turned off while its
|
||||
worker was down comes back consuming, and must be stopped when it
|
||||
returns."""
|
||||
returns.
|
||||
|
||||
Its live pool is ONE — zero slots means zero WORK, not an empty pool.
|
||||
billiard will not run one, and the process is what the enable switch lands
|
||||
on.
|
||||
"""
|
||||
control = _stub_control(monkeypatch)
|
||||
_stub_live(monkeypatch, "ml", pools={"host-a": 0}, consuming={"ml"})
|
||||
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming={"ml"})
|
||||
|
||||
result = wc.reconcile_lanes_sync({"ml": (0, False)})
|
||||
|
||||
@@ -286,9 +291,16 @@ def test_a_lane_disabled_in_settings_but_still_consuming_is_stopped(monkeypatch)
|
||||
def test_an_already_disabled_lane_is_not_cancelled_again(monkeypatch):
|
||||
"""The other half of the fixed point. `cancel_consumer` on a queue that is
|
||||
not being consumed succeeds and does nothing, so an unconditional
|
||||
reconcile would churn here forever with no symptom."""
|
||||
reconcile would churn here forever with no symptom.
|
||||
|
||||
The live pool is ONE, not zero. This fixture said zero until the floor
|
||||
landed, and it was describing a container that cannot exist — billiard
|
||||
will not run an empty pool, and the generator starts ml at one process for
|
||||
exactly that reason. A fixture in an impossible state passes for the wrong
|
||||
reason and then fails on the correct fix, which is what it did.
|
||||
"""
|
||||
control = _stub_control(monkeypatch)
|
||||
_stub_live(monkeypatch, "ml", pools={"host-a": 0}, consuming=set())
|
||||
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming=set())
|
||||
|
||||
result = wc.reconcile_lanes_sync({"ml": (0, False)})
|
||||
|
||||
@@ -692,30 +704,6 @@ def test_a_lane_at_zero_slots_is_never_shrunk_to_an_empty_pool(monkeypatch):
|
||||
assert control.shrank == [], "tried to empty a pool billiard will not empty"
|
||||
|
||||
|
||||
def test_that_lane_then_reports_nothing_to_do(monkeypatch):
|
||||
"""The fixed point. It is not enough to stop sending the doomed message —
|
||||
the reconcile must also stop CALLING the lane changed, or the log fills
|
||||
with a correction that never corrects anything."""
|
||||
_stub_control(monkeypatch)
|
||||
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming=set())
|
||||
|
||||
result = wc.reconcile_lanes_sync({"ml": (0, False)})
|
||||
|
||||
assert result["changed"] == []
|
||||
|
||||
|
||||
def test_zero_slots_still_means_zero_work(monkeypatch):
|
||||
"""The floor is one PROCESS, not one consumer. A lane at zero keeps an
|
||||
idle worker so the enable switch has something to reach, and stays off
|
||||
because its queues are cancelled."""
|
||||
control = _stub_control(monkeypatch)
|
||||
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming={"ml"})
|
||||
|
||||
wc.reconcile_lanes_sync({"ml": (0, False)})
|
||||
|
||||
assert control.cancelled == [("ml", ["host-a"])]
|
||||
|
||||
|
||||
def test_the_floor_applies_to_a_direct_resize_too(monkeypatch):
|
||||
"""Not only the reconcile — the UI dial and the autoscaler go through the
|
||||
same function, so the clamp belongs there rather than at each caller."""
|
||||
|
||||
Reference in New Issue
Block a user