[Rebase] Rebase to vllm releases/v0.22.0 (#3891)
Signed-off-by: tzhouam <tzhouam@connect.ust.hk> Signed-off-by: ZhengWG <zwg0606@gmail.com> Signed-off-by: david6666666 <530634352@qq.com> Signed-off-by: Yueqian Lin <linyueqian@outlook.com> Signed-off-by: nainiu258 <cperfect02@163.com> Signed-off-by: nainiu258 <101917677+nainiu258@users.noreply.github.com> Signed-off-by: JasonJ2021 <jasonj@zju.edu.cn> Signed-off-by: Zhou Taichang <tzhouam@connect.ust.hk> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: skf <54565339+skf-1999@users.noreply.github.com> Co-authored-by: Zheng Wengang <zwg0606@gmail.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com> Co-authored-by: WeiQing Chen <40507679+david6666666@users.noreply.github.com> Co-authored-by: SYLAR <125541396+lishunyang12@users.noreply.github.com> Co-authored-by: Yueqian Lin <linyueqian@outlook.com> Co-authored-by: nainiu258 <101917677+nainiu258@users.noreply.github.com> Co-authored-by: Jason <72191212+JasonJ2021@users.noreply.github.com> Co-authored-by: Yueqian Lin <70319226+linyueqian@users.noreply.github.com>
This commit is contained in:
62 files changed
+998
-354
No files matched your search
+113
-21
@@ -305,40 +305,132 @@ class OmniServer:
|
||||
time.sleep(2)
|
||||
raise RuntimeError(f"Server failed to start within {max_wait} seconds")
|
||||
|
||||
@staticmethod
|
||||
def _reap_zombie(proc: "psutil.Process") -> bool:
|
||||
"""Reap a zombie child process via ``os.waitpid``.
|
||||
|
||||
``psutil.Process.wait()`` uses ``pidfd_open`` + ``poll()``, which
|
||||
never fires for a zombie (the zombie is already dead and will not
|
||||
change state). Since the test process is the parent, we can reap
|
||||
the zombie directly with ``os.waitpid(pid, os.WNOHANG)`` and
|
||||
retrieve its exit code.
|
||||
|
||||
Returns True if the process was a zombie and was reaped.
|
||||
"""
|
||||
if proc.status() != psutil.STATUS_ZOMBIE:
|
||||
return False
|
||||
try:
|
||||
os.waitpid(proc.pid, os.WNOHANG)
|
||||
except ChildProcessError:
|
||||
pass
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _wait_or_reap(proc: "psutil.Process", timeout: int) -> None:
|
||||
"""Wait for *proc* to exit, handling zombie state transparently.
|
||||
|
||||
When the process is already a zombie (e.g. orchestrator thread
|
||||
hung during shutdown and the main process exited), ``pidfd_open``
|
||||
+ ``poll()`` inside ``psutil`` will never see a state change.
|
||||
Fall back to ``os.waitpid`` to reap the zombie.
|
||||
"""
|
||||
if OmniServer._reap_zombie(proc):
|
||||
return
|
||||
try:
|
||||
proc.wait(timeout=timeout)
|
||||
except psutil.TimeoutExpired:
|
||||
OmniServer._reap_zombie(proc)
|
||||
|
||||
def _kill_process_tree(self, pid):
|
||||
"""Kill the process tree rooted at *pid*.
|
||||
|
||||
Terminate the parent **first** so the OmniServer can gracefully shut
|
||||
down its stage-engine children through the orchestrator. This avoids
|
||||
the ``subprocess died unexpectedly`` ERROR that the APIServer monitor
|
||||
thread logs when children are killed before the parent, which in turn
|
||||
can cause CI watchdogs to false-trigger on the upstream ``Shutdown
|
||||
initiated`` message.
|
||||
|
||||
When the parent does not exit within the grace period (e.g. CPU-
|
||||
offloaded workers stuck in CUDA D-state), the method falls back to
|
||||
killing children first so the parent can be reaped cleanly.
|
||||
"""
|
||||
try:
|
||||
parent = psutil.Process(pid)
|
||||
children = parent.children(recursive=True)
|
||||
all_pids = [pid] + [child.pid for child in children]
|
||||
|
||||
for child in children:
|
||||
try:
|
||||
child.terminate()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
_, still_alive = psutil.wait_procs(children, timeout=10)
|
||||
|
||||
for child in still_alive:
|
||||
try:
|
||||
child.kill()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
# 1. Terminate the parent first — let it run its graceful
|
||||
# shutdown cascade (orchestrator → stage pools → engine cores).
|
||||
try:
|
||||
parent.terminate()
|
||||
parent.wait(timeout=10)
|
||||
except (psutil.NoSuchProcess, psutil.TimeoutExpired):
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
# 2. Give the parent time to shut down its children cleanly.
|
||||
parent_exited = False
|
||||
try:
|
||||
parent.wait(timeout=15)
|
||||
parent_exited = True
|
||||
except psutil.NoSuchProcess:
|
||||
parent_exited = True
|
||||
except psutil.TimeoutExpired:
|
||||
parent_exited = OmniServer._reap_zombie(parent)
|
||||
|
||||
if not parent_exited:
|
||||
# Parent is stuck — children (e.g. CPU-offloaded CFG workers)
|
||||
# are likely in uninterruptible sleep. Kill children first
|
||||
# so the parent can be reaped without lingering as a zombie.
|
||||
for child in children:
|
||||
try:
|
||||
child.kill()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
psutil.wait_procs(children, timeout=5)
|
||||
try:
|
||||
parent.kill()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
OmniServer._wait_or_reap(parent, timeout=5)
|
||||
else:
|
||||
# Parent exited cleanly — clean up any remaining children.
|
||||
for child in children:
|
||||
try:
|
||||
if child.is_running():
|
||||
child.terminate()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
gone, still_alive = psutil.wait_procs(children, timeout=10)
|
||||
|
||||
for child in still_alive:
|
||||
try:
|
||||
child.kill()
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
try:
|
||||
if parent.is_running() and not OmniServer._reap_zombie(parent):
|
||||
parent.kill()
|
||||
parent.wait(timeout=10)
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
# 3. Final sweep — ``kill -9`` anything that escaped.
|
||||
time.sleep(1)
|
||||
alive_processes = []
|
||||
for check_pid in all_pids:
|
||||
if psutil.pid_exists(check_pid):
|
||||
alive_processes.append(check_pid)
|
||||
alive_processes: list[int] = []
|
||||
for child in children:
|
||||
try:
|
||||
if child.is_running():
|
||||
alive_processes.append(child.pid)
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
# Only count the parent as alive if it is NOT a zombie
|
||||
# (zombies are already dead — just waiting to be reaped).
|
||||
try:
|
||||
if parent.is_running() and parent.status() != psutil.STATUS_ZOMBIE:
|
||||
alive_processes.append(parent.pid)
|
||||
except psutil.NoSuchProcess:
|
||||
pass
|
||||
|
||||
if alive_processes:
|
||||
print(f"Warning: Processes still alive: {alive_processes}")
|
||||
|
||||
Reference in new issue
Block a user