_ops_stop_keep_gateway.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """停掉**组件服务**, 保留网关 —— 给运维控制台用 (2026-09-12)。
  4. 为什么不能直接 `guanlan.py stop`: 那个会把网关也停掉, 而控制台页面正是网关提供的 ——
  5. 按钮刚点完页面就没了, 再也没法"启动服务"。所以这里只停 detail/cms/sim/sim_sys/viewer,
  6. 网关(28084)留着, 页面继续可用, 并如实报告"哪些还占着端口"。
  7. 复用 guanlan.py 的 kill/alive/services (同一套 taskkill /T /F 语义), 不另造一套。
  8. """
  9. from __future__ import annotations
  10. import pathlib
  11. import sys
  12. import time
  13. ROOT = pathlib.Path(__file__).resolve().parents[1]
  14. sys.path.insert(0, str(ROOT))
  15. import guanlan as G # noqa: E402
  16. KEEP = {'gateway'}
  17. def main() -> int:
  18. c = G.cfg()
  19. pids = G.jload(G.PIDS) if G.PIDS.exists() else {}
  20. stopped = kept = 0
  21. for name, port, _ in G.services(c):
  22. if name in KEEP:
  23. kept += 1
  24. print(f' 保留 {name} 端口 {port} (控制台本体)')
  25. continue
  26. v = pids.get(name) or {}
  27. pid = v.get('pid')
  28. if pid and G.alive(pid):
  29. G.kill(pid)
  30. print(f' 停 {name} pid {pid}')
  31. stopped += 1
  32. elif G.up(c['host'], port):
  33. print(f' [!] {name} 端口 {port} 在监听, 但 pids.json 里没有活进程 —— 不是本启动器起的, 不动它')
  34. else:
  35. print(f' - {name} 本来就没在跑')
  36. pids.pop(name, None)
  37. G.PIDS.write_text(__import__('json').dumps(pids, ensure_ascii=False, indent=1), encoding='utf-8')
  38. time.sleep(1.5)
  39. left = [f'{n}:{p}' for n, p, _ in G.services(c) if n not in KEEP and G.up(c['host'], p)]
  40. print(f'\n已停 {stopped} 个组件服务, 保留 {kept} 个 (网关)。')
  41. print(f'仍占端口的: {", ".join(left) if left else "无"}')
  42. print('页面现在应显示"无产物/服务未运行"; 要恢复请点控制台里的"启动服务"。')
  43. return 0
  44. if __name__ == '__main__':
  45. for _s in (sys.stdout, sys.stderr):
  46. try: _s.reconfigure(errors='replace')
  47. except Exception: pass
  48. sys.exit(main())