perf(process): wake waiters on background completion (#45831)
This commit is contained in:
@@ -129,6 +129,7 @@ class ProcessSession:
|
||||
_watch_cooldown_until: float = field(default=0.0, repr=False)
|
||||
_watch_strike_candidate: bool = field(default=False, repr=False)
|
||||
_watch_consecutive_strikes: int = field(default=0, repr=False)
|
||||
_completion_event: threading.Event = field(default_factory=threading.Event, repr=False)
|
||||
_lock: threading.Lock = field(default_factory=threading.Lock)
|
||||
_reader_thread: Optional[threading.Thread] = field(default=None, repr=False)
|
||||
_pty: Any = field(default=None, repr=False) # ptyprocess handle (when use_pty=True)
|
||||
@@ -870,6 +871,7 @@ class ProcessRegistry:
|
||||
with self._lock:
|
||||
was_running = self._running.pop(session.id, None) is not None
|
||||
self._finished[session.id] = session
|
||||
session._completion_event.set()
|
||||
self._write_checkpoint()
|
||||
|
||||
# Only enqueue completion notification on the FIRST move. Without
|
||||
@@ -1093,6 +1095,8 @@ class ProcessRegistry:
|
||||
|
||||
while time.monotonic() < deadline:
|
||||
session = self._refresh_detached_session(session)
|
||||
if session is None:
|
||||
return {"status": "not_found", "error": f"No process with ID {session_id}"}
|
||||
# Reconcile against real child state — guards against orphaned-
|
||||
# pipe reader hangs where the reader is blocked but the direct
|
||||
# child has already exited (issue #17327).
|
||||
@@ -1118,7 +1122,10 @@ class ProcessRegistry:
|
||||
result["timeout_note"] = timeout_note
|
||||
return result
|
||||
|
||||
time.sleep(1)
|
||||
remaining = deadline - time.monotonic()
|
||||
if remaining <= 0:
|
||||
break
|
||||
session._completion_event.wait(timeout=min(1.0, remaining))
|
||||
|
||||
result = {
|
||||
"status": "timeout",
|
||||
|
||||
Reference in New Issue
Block a user