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
This commit is contained in:
316
ultimate_shutdown_tool.py
Normal file
316
ultimate_shutdown_tool.py
Normal file
@@ -0,0 +1,316 @@
|
||||
#!/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)
|
||||
Reference in New Issue
Block a user