Compare commits

...

4 Commits

Author SHA1 Message Date
Lofu 311d816456
Merge a867b44867 into f591245540 2026-01-11 20:24:06 +08:00
SengokuCola f591245540 update:更新rm和cl 2026-01-11 19:31:56 +08:00
Ronifue a867b44867 fix: 重构,避免反复创建和销毁内核对象 2025-12-24 12:06:44 +08:00
Ronifue 5b38423a89 fix: 修复了当 Runner 进程意外退出时残留 Worker 孤儿进程的问题 2025-12-24 11:56:49 +08:00
3 changed files with 68 additions and 1 deletions

View File

@ -58,7 +58,7 @@ MaiBot 不仅仅是一个机器人,她致力于成为一个活跃在 QQ 群聊
## 🔥 更新和安装
> **最新版本: v0.12.1** ([📄 更新日志](changelogs/changelog.md))
> **最新版本: v0.12.2** ([📄 更新日志](changelogs/changelog.md))
- **下载**: 前往 [Release](https://github.com/MaiM-with-u/MaiBot/releases/) 页面下载最新版本
- **启动器**: [Mailauncher](https://github.com/MaiM-with-u/mailauncher/releases/) (仅支持 MacOS, 早期开发中)

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()

View File

@ -1,4 +1,13 @@
# Changelog
## [0.12.2] - 2025-1-11
### 功能更改
- 优化私聊wait逻辑
- 超时时强制引用回复
- 修复部分适配器断联问题
- 修复表达反思配置未生效
- 优化记忆检索逻辑
- 更新readme
## [0.12.1] - 2025-12-31
### 🌟 主要更新
- 添加年度总结可以在webui查看