Add regression test for the GET /api/v1/runs endpoint - #540
Draft
LudovicoRighi wants to merge 3 commits into
Draft
Add regression test for the GET /api/v1/runs endpoint#540LudovicoRighi wants to merge 3 commits into
GET /api/v1/runs endpoint#540LudovicoRighi wants to merge 3 commits into
Conversation
Collaborator
Author
|
The test fails on latest |
This reverts commit 80a547a.
Collaborator
Author
|
And passes after reverting 80a547a |
LudovicoRighi
force-pushed
the
lrighi/regression-test
branch
from
July 10, 2026 18:25
00664e2 to
1c4b452
Compare
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.
#539 moved
/runsserialization off the event loop into a background thread (asyncio.to_thread) to stop it blocking the loop on large, unfiltered queries. This fixes the blocking, but introduces a data race.Why #539 is broken
Before #539,
runs_to_jsoran synchronously on the event loop. It contains noawait, so it was atomic with respect to every other coroutine — nothing could mutate a run mid-serialization. Slow, but safe.Under
to_thread, serialization runs concurrently with the event loop, which keeps driving the run state machine (_process_updates→Apsis._transition) over the sameRunobjects being serialized.run_to_summary_jsoiteratesrun.times.items()whileRun._transitionmutates that dict in place (self.times[state.name] = ...). The result:The likelihood scales with exactly the case #539 targets — many runs → long serialization window → more transitions land inside it — so it's not a corner case. (
run.metais aliased into the JSO and also mutated in place by_transition, so it's exposed the same way.)The test
test/unit/test_runs_endpoint_race.pydrives the realapi.runshandler in process (mock DB — no server, network, or real Apsis) with a background task transitioning runs, and asserts the handler never crashes.mainwith theRuntimeErrorabove.The race is probabilistic per call, so the test serves a large run set and repeats the call several times; at these sizes a single buggy call crashes with probability well above 1/2, making a false pass negligible while a correct (atomic) implementation passes every call. It reproduces at Python's default thread-switch interval — no scheduler tuning.
Scope
This PR adds only the failing test to pin down the regression. The fix is deliberately left to follow-up discussion.
cc @gusostow