Repository navigation
test(support): re-arm time_limit's alarm so a swallowed timeout cannot hang a worker (#1892) - #1893
Conversation
|
Verdict: NEEDS CHANGES at
Required: no test pins the
The flag is the exit-path race fix carried over from #1891's review, so it needs a test that fails without it. The reviewer validated one. It patches Not blocking: a fire between the body ending and the generator resuming, inside |
…t hang a worker (#1892) - time_limit's handler re-arms the alarm for one second before each raise, so a TimeoutError dropped by a finaliser or an `except OSError` is followed by another until the body leaves the `with`. - A flag set first on the way out turns a repeat already due into a no-op; the repeat is cancelled and the previous handler and pending alarm are restored on every exit, as before. The docstring names the window inside contextlib's `__exit__` that pure Python cannot close. - TimeLimitTests pins the repeat through a finaliser and an `except OSError`, that a repeat landing on the way out does nothing, that nothing stays armed after any exit, and that an enclosing alarm survives a repeat. - Every body there that waits for the deadline is bounded and fails by name, so a lost deadline fails in seconds instead of hanging the worker. Closes #1892
3c38d26 to
a525629
Compare
|
Verdict: GOOD TO GO at
|
|
Coverage: 90.06% (unit tier, Python 3.15,
Per-file detail: the |
Please follow the guide below
You will be asked some questions, please read them carefully and answer honestly
Put an
xinto all the boxes [ ] relevant to your pull request (like that [x])Use Preview tab to see how your pull request will actually look like
Searched for similar pull requests
Followed the coding style (
make pylint,make mypy,make isort)make testpasses, and a test case covers the change. Narrow runs only, listed below.Added a changelog entry under
docs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible: N/A — centralised in docs(changelog): shared 1.5.0 changelog — long-lived, merges last (#610, #616, #617, #618, #620) #657What is the purpose of your pull request?
Tick the commit type your subject line carries.
fix— corrects a defectfeat— adds a featureperf— changes performance, not behaviourrefactor— changes neither behaviour nor performancetest— tests onlydocs— documentation onlyci— workflows or build toolingrelease— bumps the version or rolls up a distributionchore— anything elsetests/_support.time_limitarmed oneSIGALRMand raisedTimeoutErroronce. As #1891 found for the generator's deadline, that single raise can be lost. A finaliser sends it tosys.unraisablehook, and anexcept OSErrorswallows it becauseTimeoutErroris anOSError. The body then runs until pytest-timeout's 900s backstop kills the xdist worker.Fix. The handler re-arms
alarm(1)each time it raises. The first thing the exit path does is set a flag that makes any due repeat a no-op. After that it cancels the alarm, restores the previous handler, and restores the outer alarm minus the body's seconds, as before.Tests. New
TimeLimitTestscases cover:__del__, gated withsys.version_infoon 3.8+;except OSError;Every waiting body gives up after 10s, which includes the two existing unbounded
while True: passloops. Againstmain's_support.py, 5 of the new tests fail with "did not interrupt the body within 10s" or5 != 1. The test file passed 20/20 runs.Not done: sending pytest-timeout's stack dump somewhere visible under xdist. It could not be checked without xdist and pytest-timeout installed here.
Closes #1892