Files
momentry_core/ultimate_shutdown_tool.py
Warren b54c2def30 feat: add migrations, test scripts, and utility tools
- Add database migrations (006-028) for face recognition, identity, file_uuid
- Add test scripts for ASR, face, search, processing
- Add portal frontend (Tauri)
- Add config, benchmark, and monitoring utilities
- Add model checkpoints and pretrained model references
2026-04-30 15:11:53 +08:00

317 lines
9.1 KiB
Python

#!/opt/homebrew/bin/python3.11
"""
终极关机工具 - Ultimate Shutdown Tool
使用更彻底的方法停止所有服务,解决进程检测和权限问题
Ultimate tool for stopping all services, solving process detection and permission issues
"""
import os
import sys
import time
import signal
import subprocess
import psutil
from datetime import datetime
def run_command(cmd, timeout=30):
"""运行命令并返回输出"""
try:
result = subprocess.run(
cmd, shell=True, capture_output=True, text=True, timeout=timeout
)
return result.returncode == 0, result.stdout.strip()
except subprocess.TimeoutExpired:
return False, f"超时 ({timeout}s)"
except Exception as e:
return False, str(e)
def find_processes(keywords):
"""查找包含关键字的进程"""
processes = []
for proc in psutil.process_iter(["pid", "name", "cmdline"]):
try:
cmdline = " ".join(proc.info["cmdline"]) if proc.info["cmdline"] else ""
name = proc.info["name"] or ""
for keyword in keywords:
if keyword in cmdline or keyword in name:
processes.append(proc)
break
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
return processes
def stop_process_tree(pid, timeout=10):
"""停止进程树(父进程和所有子进程)"""
try:
parent = psutil.Process(pid)
children = parent.children(recursive=True)
# 先停止子进程
for child in children:
try:
child.terminate()
except:
pass
# 停止父进程
parent.terminate()
# 等待进程结束
try:
parent.wait(timeout=timeout)
except psutil.TimeoutExpired:
alive = [parent] + children
else:
alive = []
# 检查子进程
for child in children:
try:
if child.is_running():
alive.append(child)
except:
pass
# 如果还有存活的,强制停止
for p in alive:
try:
p.kill()
except:
pass
return len(alive) == 0
except psutil.NoSuchProcess:
return True
except Exception as e:
print(f"停止进程 {pid} 失败: {e}")
return False
def stop_service(
service_name, process_keywords, stop_commands=None, sudo_commands=None
):
"""停止服务"""
print(f"\n停止 {service_name}...")
# 1. 查找进程
processes = find_processes(process_keywords)
print(f" 找到 {len(processes)} 个进程")
# 2. 执行停止命令(如果有)
if stop_commands:
for cmd in stop_commands:
print(f" 执行命令: {cmd}")
success, output = run_command(cmd, timeout=15)
if not success:
print(f" 命令失败: {output}")
# 3. 执行 sudo 命令(如果需要)
if sudo_commands:
for cmd in sudo_commands:
print(f" 执行 sudo 命令: {cmd}")
sudo_cmd = f"echo 'accusys' | sudo -S {cmd}"
success, output = run_command(sudo_cmd, timeout=15)
if not success:
print(f" sudo 命令失败: {output}")
# 4. 等待
time.sleep(5)
# 5. 检查并停止进程树
processes = find_processes(process_keywords)
if processes:
print(f" 仍有 {len(processes)} 个进程在运行,停止进程树...")
for proc in processes:
stop_process_tree(proc.pid, timeout=5)
# 6. 最终检查
time.sleep(3)
remaining = find_processes(process_keywords)
if remaining:
print(f"{service_name} 仍在运行 ({len(remaining)} 个进程)")
return False
else:
print(f"{service_name} 已停止")
return True
def main():
print("=" * 60)
print("终极关机工具")
print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 60)
# 服务定义
services = [
{
"name": "AI 处理器",
"keywords": [
"asr_processor",
"ocr_processor",
"yolo_processor",
"face_processor",
"pose_processor",
"cut_processor",
"asrx_processor",
"caption_processor",
"story_processor",
],
"stop_commands": None,
"sudo_commands": None,
},
{
"name": "Momentry 服务",
"keywords": ["momentry server", "momentry worker", "momentry_playground"],
"stop_commands": None,
"sudo_commands": None,
},
{
"name": "MCP 服务器",
"keywords": [
"mcp-server-redis",
"mcp-server-postgres",
"mcp-server-filesystem",
"mcp-server-qdrant",
"mongodb-mcp-server",
"gitea-mcp-server",
],
"stop_commands": None,
"sudo_commands": None,
},
{
"name": "应用服务",
"keywords": ["php-fpm", "n8n", "ollama", "gitea web", "sftpgo serve"],
"stop_commands": None,
"sudo_commands": None,
},
{
"name": "Caddy",
"keywords": ["caddy"],
"stop_commands": None,
"sudo_commands": ["pkill -TERM caddy", "pkill -KILL caddy"],
},
{
"name": "Redis",
"keywords": ["redis-server"],
"stop_commands": ["redis-cli shutdown"],
"sudo_commands": None,
},
{
"name": "PostgreSQL",
"keywords": ["postgres"],
"stop_commands": [
"pg_ctl -D /Users/accusys/momentry/var/postgresql stop -m fast"
],
"sudo_commands": None,
},
{
"name": "MongoDB",
"keywords": ["mongod"],
"stop_commands": None,
"sudo_commands": [
"mongod --dbpath /opt/homebrew/var/mongodb --shutdown",
"pkill -TERM mongod",
"pkill -KILL mongod",
],
},
{
"name": "MariaDB",
"keywords": ["mariadbd"],
"stop_commands": ["mysqladmin -u root shutdown"],
"sudo_commands": None,
},
{
"name": "Qdrant",
"keywords": ["qdrant"],
"stop_commands": None,
"sudo_commands": None,
},
]
results = []
# 停止所有服务
for service in services:
success = stop_service(
service["name"],
service["keywords"],
service.get("stop_commands"),
service.get("sudo_commands"),
)
results.append((service["name"], success))
# 最终检查
print("\n" + "=" * 60)
print("最终状态检查")
print("=" * 60)
all_stopped = True
for service_name, success in results:
if success:
print(f"{service_name}: 已停止")
else:
print(f"{service_name}: 仍在运行")
all_stopped = False
# 列出所有仍在运行的进程
if not all_stopped:
print("\n仍在运行的进程:")
print("-" * 40)
all_keywords = []
for service in services:
all_keywords.extend(service["keywords"])
remaining = find_processes(all_keywords)
for proc in remaining:
try:
cmdline = (
" ".join(proc.info["cmdline"])
if proc.info["cmdline"]
else proc.info["name"]
)
print(f" PID {proc.pid}: {cmdline[:100]}...")
except:
print(f" PID {proc.pid}: (无法获取信息)")
print("\n" + "=" * 60)
if all_stopped:
print("✅ 所有服务已停止!")
print("系统可以安全关机。")
else:
print("⚠️ 部分服务仍在运行。")
print("建议:")
print("1. 手动检查并停止剩余进程")
print("2. 使用 'sudo shutdown -h now' 强制关机")
print("3. 系统会在关机时处理剩余进程")
# 生成报告
report_file = f"/tmp/ultimate_shutdown_report_{int(time.time())}.txt"
with open(report_file, "w") as f:
f.write("终极关机工具报告\n")
f.write(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write("=" * 40 + "\n")
f.write(f"结果: {'成功' if all_stopped else '部分成功'}\n\n")
f.write("服务状态:\n")
for service_name, success in results:
f.write(f" {service_name}: {'✅ 已停止' if success else '❌ 仍在运行'}\n")
print(f"\n详细报告保存到: {report_file}")
print("=" * 60)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n操作被用户中断")
sys.exit(130)
except Exception as e:
print(f"\n错误: {e}")
sys.exit(1)