mirror of https://github.com/Mai-with-u/MaiBot.git
Merge a867b44867 into b63b7a7fb9
commit
6694c618b7
58
bot.py
58
bot.py
|
|
@ -56,6 +56,7 @@ def run_runner_process():
|
||||||
# 设置环境变量,标记子进程为 Worker 进程
|
# 设置环境变量,标记子进程为 Worker 进程
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["MAIBOT_WORKER_PROCESS"] = "1"
|
env["MAIBOT_WORKER_PROCESS"] = "1"
|
||||||
|
env["MAIBOT_RUNNER_PID"] = str(os.getpid()) # 传递 Runner PID 供 Worker 监控
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
logger.info(f"正在启动 {script_file}...")
|
logger.info(f"正在启动 {script_file}...")
|
||||||
|
|
@ -175,6 +176,60 @@ def easter_egg():
|
||||||
print(rainbow_text)
|
print(rainbow_text)
|
||||||
|
|
||||||
|
|
||||||
|
def _start_parent_monitor():
|
||||||
|
"""启动父进程存活监控守护线程,检测到 Runner 终止后触发优雅退出"""
|
||||||
|
import ctypes
|
||||||
|
import signal
|
||||||
|
import threading
|
||||||
|
|
||||||
|
try:
|
||||||
|
runner_pid = int(os.environ.get("MAIBOT_RUNNER_PID", "0"))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return
|
||||||
|
if not runner_pid:
|
||||||
|
return
|
||||||
|
|
||||||
|
def is_alive_unix(pid):
|
||||||
|
return os.getppid() == pid
|
||||||
|
|
||||||
|
def trigger_exit():
|
||||||
|
# Logger 容错:解释器关闭阶段 Logger 可能已被销毁
|
||||||
|
try:
|
||||||
|
get_logger("main").warning("检测到 Runner 进程已终止,正在触发优雅退出...")
|
||||||
|
except Exception:
|
||||||
|
print("[ParentMonitor] 检测到 Runner 进程已终止,正在触发优雅退出...")
|
||||||
|
signal.raise_signal(signal.SIGINT) # 触发 KeyboardInterrupt,走正常关闭流程
|
||||||
|
|
||||||
|
def monitor():
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
# Windows: 循环外获取句柄,循环内只检查退出码,减少系统调用
|
||||||
|
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000
|
||||||
|
STILL_ACTIVE = 259
|
||||||
|
kernel32 = ctypes.windll.kernel32
|
||||||
|
handle = kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, runner_pid)
|
||||||
|
if not handle:
|
||||||
|
# 进程已不存在或无权限访问,直接触发退出
|
||||||
|
return trigger_exit()
|
||||||
|
try:
|
||||||
|
exit_code = ctypes.c_ulong()
|
||||||
|
while True:
|
||||||
|
if not kernel32.GetExitCodeProcess(handle, ctypes.byref(exit_code)):
|
||||||
|
break # API 调用失败,假定进程已退出
|
||||||
|
if exit_code.value != STILL_ACTIVE:
|
||||||
|
break # 进程已退出
|
||||||
|
time.sleep(2)
|
||||||
|
finally:
|
||||||
|
kernel32.CloseHandle(handle)
|
||||||
|
else:
|
||||||
|
# Unix: 检测 ppid 是否变化
|
||||||
|
while is_alive_unix(runner_pid):
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
trigger_exit()
|
||||||
|
|
||||||
|
threading.Thread(target=monitor, daemon=True, name="ParentMonitor").start()
|
||||||
|
|
||||||
|
|
||||||
async def graceful_shutdown(): # sourcery skip: use-named-expression
|
async def graceful_shutdown(): # sourcery skip: use-named-expression
|
||||||
try:
|
try:
|
||||||
logger.info("正在优雅关闭麦麦...")
|
logger.info("正在优雅关闭麦麦...")
|
||||||
|
|
@ -322,6 +377,9 @@ def raw_main():
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
exit_code = 0 # 用于记录程序最终的退出状态
|
exit_code = 0 # 用于记录程序最终的退出状态
|
||||||
try:
|
try:
|
||||||
|
# 启动父进程存活监控(Runner 异常退出时自动触发优雅关闭)
|
||||||
|
_start_parent_monitor()
|
||||||
|
|
||||||
# 获取MainSystem实例
|
# 获取MainSystem实例
|
||||||
main_system = raw_main()
|
main_system = raw_main()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue