Repository navigation
Three deadline tests fire the real deadline inside the held operation, not on wall time (BACKLOG #3871) - #2439
Merged
Merged
Conversation
…, not on wall time (BACKLOG #3871) test_dr_outlive_deadline (activation and release), test_reload_cancellation and test_upload_api (create row and delete row) set the request deadline to a fraction of a second. It counts from the start of the request, so on a loaded runner the auth dependencies, the body read or the file save outlasted it: the 503 came before the route started its outliving operation, and the test failed on a state the code never reached (the merge-queue failure of 2026-10-19, "not enough values to unpack (expected 1, got 0)", is the create test's form). A new tests/_deadline_capture.py, the same stand-in engine PR 2438 uses in the web console, records the middleware's own asyncio.Timeout under a 30 s deadline. The held operation fires it to now and is held until the 503 is in; the test then waits on OutlivingOperations.drain instead of polling a clock. Ledger banner: #3871 remainder done -- the three sibling tests fire the deadline inside the held operation; test_upload_api's mid-sweep test (2.0 s) is not covered.
… upload test fires it too (BACKLOG #3871) Code-review round 1. fire() records a miscount or an already-started response on the capture instead of raising on the operation's task, where the DR coordinator would catch it and write abort rows; expect_cut_off asserts it. The middleware module sees only timeout() (no Any-typed __getattr__), the deadline attribute is set through monkeypatch so it is undone, held() takes the app's OutlivingOperations from the capture, the generous deadline drops to 15 s so a failing run still ends inside the per-test timeout, and the rationale lives once, in tests/_deadline_capture.py. test_a_deadline_mid_sweep_still_writes_a_prune_row_per_deleted_file raced a 2.0 s wall-clock deadline the same way; its parked sweep thread now fires the captured deadline through call_soon_threadsafe. Proposed PR title: Three deadline tests fire the real deadline inside the held operation, not on wall time (BACKLOG #3871) Ledger banner: #3871 remainder done -- test_dr_outlive_deadline, test_reload_cancellation and test_upload_api (create, delete and mid-sweep) fire the deadline inside the held operation.
… deadlocks (BACKLOG #3871) Code-review round 2. When fire() finds no deadline, a second one, a disarmed one, or one reschedule refuses, it fires nothing, records the reason and lets the hold go, so the request ends and expect_cut_off reports the reason (also when the request raised). fired now means a deadline really was expired. The helper is registered for assert rewriting in conftest, as tests._content_free is. The mid-sweep test checks that its sweep parked before it reads the response, as it did before. Proposed PR title: Three deadline tests fire the real deadline inside the held operation, not on wall time (BACKLOG #3871) Ledger banner: #3871 remainder done -- test_dr_outlive_deadline, test_reload_cancellation and test_upload_api (create, delete and mid-sweep) fire the deadline inside the held operation.
Collaborator
Author
|
QA for head eaccaab (the Builder's line, posted by the Manager): QA -- korus roles/BUILDER.md step 11 / Level: xhigh, from the brief. Tag: none printed (findings list only, both rounds). / Rounds: 2. Findings: round 1 raised 13, round 2 raised 13, all diagnostic, robustness or cleanup, none a correctness defect in what the tests prove; most fixed in 55f7dae and eaccaab; 6 open, listed in the PR body. |
Collaborator
Author
|
Lander: enqueued at eaccaab, pinned.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Vault BACKLOG #3871, the remainder: the last three tests on the row that raced a wall-clock request deadline, plus a fourth case found in review. Together with engine PR 2438 (
test_ui_dr_outlive), this closes the row. Test-only; production code is unchanged.The race (the same in every case)
The deadline was wall time from the start of the request. When the auth dependencies, the body read, or the file save outlasted it, the 503 fired before the route reached
OutlivingOperations.run, so the test asserted on state the code never reached. The merge-queue failure oftest_upload_api.py::test_a_deadline_during_the_create_row_still_writes_it("ValueError: not enough values to unpack (expected 1, got 0)", run 39177122501) is this race: the deadline fired before or duringus.save, which removes its pair on cancellation (#2262). That is correct product behaviour.What changed
tests/_deadline_capture.py(registered for assert rewriting intests/conftest.py):capture_deadlines(monkeypatch, app)records the middleware's realasyncio.Timeout, set to a 15 s deadline that never fires on its own.capture.cut_off(), which reschedules that deadline to now, so the middleware's own 503 lands mid-operation.async with capture.held():releases the operation and waits withOutlivingOperations.drain, asserting nothing was cancelled.expect_cut_offasserts the exact 503 body.test_dr_outlive_deadline.py:park_intake, with the box active and intake unbound. All original end-state assertions are kept, plusinflight == ["DR release"]._activate_profile, with the original assertions kept.test_reload_cancellation.py: cuts off inreload_detail. It assertsinflight == ["config reload"]and no row while held, then that the row is written after the caller left and there is no interrupted row. The deaddeadlineparameter and the_waithelper are removed.test_upload_api.py:call_soon_threadsafe._settleis removed.Proof
-n auto(3000 tests)OutlivingOperations.rundelayed 0.7 s before registering), five testsPlain loops do not reproduce the flake on this box; the slowed arm does, and it reproduces the exact CI failure. Mutations, each reverted:
OutlivingOperations.runas a plain await: five tests red, also confirmed independently by the code-review skill.drainedhard-coded True: the release test red.on_cancel=lambda: None: the mid-sweep test red.Checks
-n auto.git merge-tree --write-tree origin/main eaccaab9bexited 0 at main d61284d, with a self-merge control at 0.Open findings (code review at xhigh, 2 rounds; no correctness defect in what the tests prove)
_admin_clientin test_dr_outlive_deadline keeps a deaddeadlineparameter; two other test files import it.held()cannot report the operation's own exception, becauseOutlivingOperationsexposes no task results. The outcome-row assertions cover it instead.expect_cut_offpins the 503 body literal, astest_api_request_timeout.pydoes.Proposed banner
SHIPPED -- all four tests on the row (test_ui_dr_outlive in PR 2438; test_dr_outlive_deadline, test_reload_cancellation and test_upload_api here) fire the middleware's real deadline inside the held operation instead of racing wall time (BACKLOG #3871).