Compare commits

...

6 Commits

7 changed files with 108 additions and 50 deletions

58
bot.py
View File

@ -56,6 +56,7 @@ def run_runner_process():
# 设置环境变量,标记子进程为 Worker 进程
env = os.environ.copy()
env["MAIBOT_WORKER_PROCESS"] = "1"
env["MAIBOT_RUNNER_PID"] = str(os.getpid()) # 传递 Runner PID 供 Worker 监控
while True:
logger.info(f"正在启动 {script_file}...")
@ -175,6 +176,60 @@ def easter_egg():
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
try:
logger.info("正在优雅关闭麦麦...")
@ -322,6 +377,9 @@ def raw_main():
if __name__ == "__main__":
exit_code = 0 # 用于记录程序最终的退出状态
try:
# 启动父进程存活监控Runner 异常退出时自动触发优雅关闭)
_start_parent_monitor()
# 获取MainSystem实例
main_system = raw_main()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,21 +11,21 @@
<link rel="icon" type="image/x-icon" href="/maimai.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MaiBot Dashboard</title>
<script type="module" crossorigin src="/assets/index-HQ4xq01Z.js"></script>
<script type="module" crossorigin src="/assets/index-DD4VGX3W.js"></script>
<link rel="modulepreload" crossorigin href="/assets/react-vendor-BmxF9s7Q.js">
<link rel="modulepreload" crossorigin href="/assets/router-9vIXuQkh.js">
<link rel="modulepreload" crossorigin href="/assets/utils-BqoaXoQ1.js">
<link rel="modulepreload" crossorigin href="/assets/radix-core-DyJi0yyw.js">
<link rel="modulepreload" crossorigin href="/assets/radix-extra-DmmnfeQE.js">
<link rel="modulepreload" crossorigin href="/assets/charts-simvewUa.js">
<link rel="modulepreload" crossorigin href="/assets/icons-CBTr14-W.js">
<link rel="modulepreload" crossorigin href="/assets/icons-8bdCaZgy.js">
<link rel="modulepreload" crossorigin href="/assets/codemirror-TZqPU532.js">
<link rel="modulepreload" crossorigin href="/assets/dnd-BiPfFtVp.js">
<link rel="modulepreload" crossorigin href="/assets/misc-CJqnlRwD.js">
<link rel="modulepreload" crossorigin href="/assets/reactflow-DtsZHOR4.js">
<link rel="modulepreload" crossorigin href="/assets/uppy-DFP_VzYR.js">
<link rel="modulepreload" crossorigin href="/assets/markdown-CKA5gBQ9.js">
<link rel="stylesheet" crossorigin href="/assets/index-ByrlkbsK.css">
<link rel="stylesheet" crossorigin href="/assets/index-RB5cYCSR.css">
</head>
<body>
<div id="root" class="notranslate"></div>