| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- r"""动作启动器 (2026-09-12) —— 只做一件事: 把真正的执行器 **甩开** 与网关的父子关系, 然后立刻退出。
- ## 为什么需要这层
- 网关用 `subprocess.Popen` 起的任务, 在 Windows 上是网关的**子进程**; 而 `guanlan.py stop` 用的是
- `taskkill /PID <网关> /T /F` —— `/T` 会**沿父子树把子孙一起杀**。于是:
- 在控制台点"执行重算" → 重算跑到第 6 步"重启服务" → stop 杀掉网关 → **把正在执行的重算也杀了**
- (实测: 日志停在 `[4/12] ⑥ 重启服务 (stop)` 那一行, 之后什么都没有, 服务也停在半路)
- 现在由本启动器 `Popen` 真正的执行器后**立即退出**: 执行器的父进程变成一个已退出进程, 于是它不再是
- 网关的子孙, `taskkill /T` 不会再连带杀掉它。启动器把执行器的 pid 打到 stdout 最后一行, 供父进程记账。
- 用法: python scripts/_ops_launch.py --tag rebuild --log <日志文件> -- <命令...>
- """
- from __future__ import annotations
- try:
- from app_common.app_common_guanlan.api import install_root as _install_root
- except ImportError: # 极端兜底(包结构异常时按位置上跳)
- from pathlib import Path as _P
- def _install_root(_f): return _P(_f).resolve().parents[3]
- import argparse
- import os
- import pathlib
- import subprocess
- import sys
- ROOT = _install_root(__file__)
- sys.path.insert(0, str(ROOT))
- from src import proc as _proc # 无窗口子进程 (2026-09-16 用户令: 不弹命令窗口)
- def main() -> int:
- ap = argparse.ArgumentParser()
- ap.add_argument('--tag', required=True)
- ap.add_argument('--log', required=True)
- ap.add_argument('cmd', nargs=argparse.REMAINDER)
- a = ap.parse_args()
- cmd = [c for c in a.cmd if c != '--']
- if not cmd:
- print('[X] 没给命令', file=sys.stderr); return 2
- log = pathlib.Path(a.log)
- log.parent.mkdir(parents=True, exist_ok=True)
- env = dict(os.environ, PYTHONUTF8='1', PYTHONIOENCODING='utf-8', PYTHONUNBUFFERED='1')
- # ★ 用 src.proc.spawn (CREATE_NO_WINDOW + 新进程组), **不要**再加 DETACHED_PROCESS:
- # 两者互斥 (前者=给一个没有窗口的控制台, 后者=不给控制台); 原先这里用 DETACHED,
- # 而本启动器自己可能是从"无控制台"的网关侧被拉起的, 落地实测会看到黑窗 (2026-09-16)。
- p = _proc.spawn([sys.executable, 'scripts/_ops_run.py', '--tag', a.tag, '--'] + cmd,
- log=log, env=env, cwd=ROOT)
- print(p.pid) # ← 最后一行是执行器 pid, 父进程读它
- return 0
- if __name__ == '__main__':
- sys.exit(main())
|