Skip to content

RunHandle._wait_for_acceptance can strand _accept_wait_in_progress on an async exception #1555

Description

@ChaoWao

Found by CodeRabbit while reviewing #1540; the code is on main from #1467, not in that PR's diff.

RunHandle._wait_for_acceptance (python/simpler/worker.py) sets the completion flags outside any try/finally:

assert run_id is not None
try:
    self._worker._wait_run_handle_accepted(run_id)
except BaseException:
    self._accept_wait_in_progress = False
    with self._cv:
        self._cv.notify_all()
    raise

self._launch_accepted = True
self._accept_wait_in_progress = False
with self._cv:
    self._cv.notify_all()

An async BaseException landing between the native call returning and those assigns — the GIL-reacquire window this file's own wait() docstring already reasons about — leaves _accept_wait_in_progress True forever.

That flag is load-bearing: wait() loops on it before it ever sets _terminal, so both wait() and any later _wait_for_acceptance() on the handle block indefinitely, including the unconditional handle.wait() drain in Worker.close().

Unlike the irreducible windows documented elsewhere in the file, this one is avoidable:

try:
    self._worker._wait_run_handle_accepted(run_id)
    self._launch_accepted = True
finally:
    self._accept_wait_in_progress = False
    with self._cv:
        self._cv.notify_all()

Severity: a hang rather than wrong data, and it needs an async exception in a narrow window, so low frequency — but the failure mode is an unkillable close().

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions