热重载监督者优雅响应 Ctrl+C:先等子进程收尾再回收
- run_supervisor 捕获 KeyboardInterrupt:不打 traceback、退出码归零, 给子进程 _GRACE_SECONDS=5s 自行收尾窗口(打退出日志、关连接), 超时才 taskkill /F /T;文件变更重启仍立即强杀(子进程不知情不会自己退) - main() 兜底监督循环间隙的 Ctrl+C - start.bat 改为发射器:start 新开独立控制台跑 cmd /c 命令行(非批 处理),Ctrl+C 直接停进程,规避「终止批处理操作吗(Y/N)」,发射器 即退;bat 保持纯 ASCII 防 GBK 乱码
This commit is contained in:
1 parent
6b6492dc8d
commit
d71809d144
3 files changed
+33
-5
No files matched your search
+23
-3
@@ -23,6 +23,10 @@ CHILD_ENV = "_MUSICBOT_RELOAD_CHILD"
|
||||
# 轮询间隔(秒):够快地感知保存动作,又不至于空耗 CPU
|
||||
_POLL_INTERVAL = 1.0
|
||||
|
||||
# Ctrl+C 时给子进程的自行退出窗口(秒):子进程收到同一信号正在收尾
|
||||
# (打退出日志、关连接),等它退完,超时才强杀
|
||||
_GRACE_SECONDS = 5.0
|
||||
|
||||
# 监控的文件类型(源码与订阅/环境配置——两者都在启动时读取,改了需重启)
|
||||
_WATCH_SUFFIXES = (".py", ".toml")
|
||||
|
||||
@@ -72,10 +76,20 @@ def _spawn(cmd: list[str], root: Path) -> subprocess.Popen:
|
||||
return subprocess.Popen(cmd, cwd=root, env={**os.environ, CHILD_ENV: "1"})
|
||||
|
||||
|
||||
def _terminate(proc: subprocess.Popen) -> None:
|
||||
"""结束子进程及其后代(bot 可能再拉起 Python 子进程)。"""
|
||||
def _terminate(proc: subprocess.Popen, grace: float = 0) -> None:
|
||||
"""结束子进程及其后代(bot 可能再拉起 Python 子进程)。
|
||||
|
||||
grace > 0 时先等子进程自行退出,超时才强杀——用于 Ctrl+C 收尾场景;
|
||||
文件变更重启时子进程并不知情、不会自己退,必须保持立即强杀。
|
||||
"""
|
||||
if proc.poll() is not None:
|
||||
return
|
||||
if grace:
|
||||
try:
|
||||
proc.wait(timeout=grace)
|
||||
return
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.warning(f"子进程未在 {grace:g}s 内自行退出,强制结束")
|
||||
if sys.platform == "win32":
|
||||
# terminate() 只结束直接子进程,/T 连整棵进程树一起收掉
|
||||
subprocess.run(
|
||||
@@ -103,6 +117,7 @@ def run_supervisor(cmd: list[str], root: Path) -> int:
|
||||
while True:
|
||||
logger.info("启动 bot 子进程")
|
||||
proc = _spawn(cmd, root)
|
||||
grace = 0.0
|
||||
try:
|
||||
before = snapshot(root)
|
||||
while proc.poll() is None:
|
||||
@@ -117,6 +132,11 @@ def run_supervisor(cmd: list[str], root: Path) -> int:
|
||||
else:
|
||||
# 子进程自行退出(含 Ctrl-C 透传):不重启,原样返回退出码
|
||||
return proc.returncode or 0
|
||||
except KeyboardInterrupt:
|
||||
# Ctrl+C 同时送达子进程与此监督循环:吞掉异常不打印 traceback,
|
||||
# 退出码归零,子进程的收尾交给下方带宽限的回收
|
||||
grace = _GRACE_SECONDS
|
||||
return 0
|
||||
finally:
|
||||
# 正常退出时是空操作;重启与 Ctrl-C 中断时回收子进程,避免孤儿
|
||||
_terminate(proc)
|
||||
_terminate(proc, grace)
|
||||
Reference in new issue
Block a user