Skip to content

test(conftest): skip the tier-guard lock under an ancestor's shared hold (#2082) - #2086

Merged
JarryShaw merged 1 commit into
mainfrom
test/2082-tier-guard-nested-hold
Oct 23, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
test/2082-tier-guard-nested-hold

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner

What is the purpose of your pull request?

  • test — adding missing tests or correcting existing tests

Description of your pull request and other information

Part of #2082. It fixes the deadlock that ate 600 s of GraalPy's last shard in 3 of the last 4 full runs. #2083, #2084 and #2085 hold the leg's other failures.

  • What happens:
    • test_module_isolation holds the tier-guard lock shared while its nested pytest runs.
    • Since test: the tier guard's blocking flock deadlocks GraalPy's xdist session #1977's writer gate, a queued writer (ProbeWriteLockTests) blocks new shared holds.
    • So the nested run's tests queue behind the writer, while the writer waits on the outer hold.
    • Only the nested run's 600 s timeout breaks the cycle. In job 120240454095, three tests finished together at 05:10:33 after a silent stretch at load 0.22.
  • It isn't GraalPy-specific: GraalPy's slow startup just gives the writer time to queue.
  • The fix: tests/conftest.py's shared hold now sets PCAPKIT_TEST_TIER_GUARD_HELD to the lock path while it lasts. A child process that inherits it for the same lock skips its own request, because the parent's hold already keeps the writer out. The out-of-date "nothing here triggers it" comment is corrected.
  • Tests: ProbeLockNestedRunTests recreates the deadlock with a real child process and a writer queued at the gate. With the fix disabled it times out; with it, it passes in 0.24 s. It also checks that the variable lasts only for the hold and that another lock's path is ignored.
  • Results: the tier-guard, isolation, support-helper and docs tests give 237 passed.

…old (#2082)

A unit-tier test that runs a nested pytest holds the probe/scan lock shared
for the whole run. Since the writer gate (#1977), a writer arriving
meanwhile holds the gate while it waits on that hold, so the nested run's
own shared requests queue behind it and the outer hold waits on the nested
run: a deadlock only subprocess.run's 600 s timeout ended. On GraalPy's
experimental leg, test_module_isolation failed this way in three runs, with
ProbeWriteLockTests and another reader stalled ~590 s alongside it.

The reader hold now exports PCAPKIT_TEST_TIER_GUARD_HELD, naming the lock
file, for its duration; a process that inherits it for the same lock file
skips the request, since the ancestor's hold already keeps the writer out.

ProbeLockNestedRunTests reproduces the deadlock with a real child process
(it times out at the gate without the fix) and pins the variable's scope.
@JarryShaw JarryShaw added test Pull requests that add or correct tests (test: subject prefix) review: running A cross-review is in flight against the current head - no verdict yet labels Oct 23, 2026
@JarryShaw JarryShaw moved this to In review in PyPCAPKit Oct 23, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO at e20ee37e5 (Sonnet cross-review).

  • The cycle: job 120240454095 stalls from 05:00:53 to 05:10:33, and the nested pytest had finished one test ([b'.']) before blocking. The gate code at 7f7c7cf8b and on main explains why. A reader takes the gate shared and then the lock. A writer holds the gate while it waits for the lock, and the outer shared hold waits on its subprocess.
  • Skipping is sound: the parent's hold spans the whole subprocess.run, and the variable must name the exact lock path. A finally restores or removes it. xdist workers start before any hold, so they still lock. A writer in a child still waits, exactly as before.
  • The new test: with the fix removed it times out after about 120 s, and with it restored it passes in 0.24 s.
  • One residual, judged negligible: a child left behind by a parent killed without cleanup would run unlocked. subprocess.run kills the child on timeout.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage: 91.54% (unit tier, Python 3.15, e20ee37e5, Unit Tests run success)

Package Statements Missed Branches Partial Cover
pcapkit (top level) 104 4 20 2 95.16%
pcapkit/const 19599 880 2618 866 92.12%
pcapkit/corekit 2565 71 812 37 96.56%
pcapkit/dumpkit 282 3 102 3 98.44%
pcapkit/foundation 2930 23 1022 25 98.79%
pcapkit/interface 138 4 52 3 96.32%
pcapkit/protocols 17414 219 4574 185 98.14%
pcapkit/toolkit 869 36 298 10 95.20%
pcapkit/utilities 473 7 136 5 98.03%
pcapkit/vendor 4432 1988 1018 167 51.87%

Per-file detail: the coverage-html artifact of this run.

@JarryShaw

Copy link
Copy Markdown
Owner Author

Ready to merge at e20ee37e5: the review is GOOD TO GO and CI is complete (56 passed, 0 failed). The ordering leg ran 2041 tests with 0 failures, and the 3.8–3.10 KTLO legs show 0 failing tests. The branch is one test-only commit behind main (b561d0f), so no rebase is needed.

@JarryShaw
JarryShaw merged commit bfa2469 into main Oct 23, 2026
64 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in PyPCAPKit Oct 23, 2026
@JarryShaw
JarryShaw deleted the test/2082-tier-guard-nested-hold branch October 23, 2026 13:46
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Oct 23, 2026
@JarryShaw JarryShaw added this to the PyPCAPKit v1.5 milestone Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test Pull requests that add or correct tests (test: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant