mirror of
https://github.com/MemeMeow-Studio/MemeMeow.git
synced 2026-10-16 20:31:33 +08:00
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""OpenCode 子进程 supervisor。
|
|
|
|
只有该模块负责进程组终止和 ``waitpid`` 收束判定;executor 业务层据此决定
|
|
cancelled、timeout 或 unknown_execution,不自行发送信号。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import signal
|
|
import subprocess
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ProcessTermination:
|
|
"""进程收束结果,``reaped`` 表示父进程已被 wait 确认回收。"""
|
|
|
|
reaped: bool
|
|
returncode: int | None
|
|
|
|
|
|
class ProcessSupervisor:
|
|
"""按进程组管理单个 OpenCode 子进程。"""
|
|
|
|
def terminate(self, process: subprocess.Popen[Any], *, grace_seconds: float = 2.0) -> ProcessTermination:
|
|
"""先发送 SIGTERM,超时后发送 SIGKILL,并返回可证明的回收状态。"""
|
|
if process.poll() is not None:
|
|
return ProcessTermination(True, process.returncode)
|
|
try:
|
|
os.killpg(process.pid, signal.SIGTERM)
|
|
process.wait(timeout=grace_seconds)
|
|
except (OSError, subprocess.TimeoutExpired):
|
|
try:
|
|
os.killpg(process.pid, signal.SIGKILL)
|
|
process.wait(timeout=grace_seconds)
|
|
except (OSError, subprocess.TimeoutExpired):
|
|
return ProcessTermination(process.poll() is not None, process.returncode)
|
|
return ProcessTermination(process.poll() is not None, process.returncode)
|
|
|
|
def wait(self, process: subprocess.Popen[Any], *, timeout_seconds: float) -> ProcessTermination:
|
|
"""等待进程终态;超时不擅自吞掉未知状态,由调用方决定是否终止。"""
|
|
try:
|
|
process.wait(timeout=timeout_seconds)
|
|
except subprocess.TimeoutExpired:
|
|
return ProcessTermination(False, process.poll())
|
|
return ProcessTermination(True, process.returncode)
|
|
|
|
|
|
__all__ = ["ProcessSupervisor", "ProcessTermination"]
|