Backend-aware timeout in `maybe_expect_raises`
Default `timeout` from `int = 3` → `int|None = None`; when unset, pick a backend-aware value. Fork-based backends (`main_thread_forkserver`) need real headroom bc actor spawn + IPC ctx-exit + msg-validation error path is much heavier than under `trio` backend — especially under cross-pytest-stream contention (#451). Defaults: - `main_thread_forkserver` → 30s - everything else → 3s (unchanged) Empirical flake history that motivated 30s as the floor on fork backends (all from `test_basic_payload_spec`): - 3s → all-valid variant flaked w/ `TooSlowError` - 8s → `invalid-return` variant flaked w/ `Cancelled` (surfaced instead of `MsgTypeError` bc the outer `fail_after` fired mid-error-path) - 15s → flaked under cross-pytest-stream contention 30s gives plenty of headroom while still failing-loud on a genuine hang. Callers can opt out by passing an explicit `timeout=` kw. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-codesubint_forkserver_backend
parent
3c366cac13
commit
060f7d24c4
|
|
@ -55,12 +55,37 @@ async def maybe_expect_raises(
|
|||
raises: BaseException|None = None,
|
||||
ensure_in_message: list[str]|None = None,
|
||||
post_mortem: bool = False,
|
||||
timeout: int = 3,
|
||||
# NOTE, `None` selects a backend-aware default below —
|
||||
# see `_BACKEND_TIMEOUT_DEFAULTS` for rationale. Caller
|
||||
# can override with an explicit value to opt out.
|
||||
timeout: int|None = None,
|
||||
) -> None:
|
||||
'''
|
||||
Async wrapper for ensuring errors propagate from the inner scope.
|
||||
|
||||
'''
|
||||
if timeout is None:
|
||||
# Pick a backend-aware default. Fork-based backends
|
||||
# (`main_thread_forkserver`) need much more headroom
|
||||
# because actor spawn + IPC ctx-exit + msg-validation
|
||||
# error path takes longer than under `trio` backend
|
||||
# — especially under cross-pytest-stream contention
|
||||
# (#451). `test_basic_payload_spec` empirically:
|
||||
# - 3s flaked all-valid variant (`TooSlowError`)
|
||||
# - 8s flaked `invalid-return` variant
|
||||
# (`Cancelled` surfaced instead of `MsgTypeError`
|
||||
# because `fail_after` fired mid-error-path)
|
||||
# - 15s flaked under cross-stream contention
|
||||
# 30s for fork-based gives plenty of headroom while
|
||||
# still failing-loud on a genuine hang. Other
|
||||
# backends keep the original 3s.
|
||||
from tractor.spawn import _spawn as _spawn_mod
|
||||
timeout = (
|
||||
30
|
||||
if _spawn_mod._spawn_method == 'main_thread_forkserver'
|
||||
else 3
|
||||
)
|
||||
|
||||
if tractor.debug_mode():
|
||||
timeout += 999
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue