Add `pytest-timeout` to fail hanging tests fast
featuregood first issuehelp wanted
# Feature
## Thesis
Add [`pytest-timeout`](https://pypi.org/project/pytest-timeout/) to the test dependencies and enable a global per-test timeout, so a hanging test fails fast and names itself instead of stalling the job.
```toml
[dependency-groups]
unit-test = [
# ...
"pytest-timeout>=2.4,<3",
]
[tool.pytest.ini_options]
# Fail hanging tests instead of blocking CI:
timeout = 30
timeout_method = "thread"
```
Tests that legitimately need longer raise their own budget with the marker:
```python
@pytest.mark.timeout(120)
def test_something_genuinely_slow() -> None: ...
```
## Reasoning
- **Nothing currently bounds a hang.** Only `.github/workflows/relator.yml` sets `timeout-minutes`; `test.yml`, `test-extras.yml`, `build-wheels.yml` and `codspeed.yml` do not, so a single deadlocked test burns the GitHub Actions default of **6 hours per job** — multiplied across the Python/Django matrix.
- **The suite has real hang-prone surface.** `asyncio_mode = 'auto'` means every async test can deadlock on an unawaited future; `tests/test_integration/test_throttling/test_backends/test_redis_backend/` talks to a live Redis/Valkey; the streaming tests consume generators; the smoke tests spawn subprocesses. Today a wedged backend looks like "CI is slow", not "CI is broken".
- **Attribution.** A job-level `timeout-minutes` kills the run without telling you which test hung. `pytest-timeout` dumps the stack of the offending test and keeps going, which is the difference between a five-minute fix and a bisect.
- **Locally too.** The same protection applies to `just unit`, where a hang currently requires a manual Ctrl-C and offers no traceback.
- **Cheap.** One pure-Python dev dependency, no runtime impact on the shipped package.
### Notes / open questions
- It has to go in the `unit-test` group specifically: that group is the minimal one installed by `cibuildwheel`, and with `--strict-config` in `addopts` an unknown `timeout` ini key would make pytest error out anywhere the plugin isn't installed.
- `timeout_method = "thread"` behaves the same on every platform (relevant for the Windows wheel jobs); `signal` gives a slightly nicer traceback but is POSIX-only. Happy to go with either.
- The `30`s default is a starting point — it should be set above the slowest current test so the change is a no-op for a green suite. Worth a `--durations` run to pick the number.
关闭于 24 天前 5 条评论