diff --git a/Module/FlaskSubprocessManager.py b/Module/FlaskSubprocessManager.py index 997c812..97755e4 100644 --- a/Module/FlaskSubprocessManager.py +++ b/Module/FlaskSubprocessManager.py @@ -18,7 +18,7 @@ class FlaskSubprocessManager: """Flask 子进程守护 + 看门狗 + 稳定增强""" _instance: Optional['FlaskSubprocessManager'] = None - _lock = threading.Lock() + _lock = threading.RLock() def __new__(cls): with cls._lock: @@ -42,6 +42,9 @@ class FlaskSubprocessManager: self._fail_count = 0 self._last_restart_time = 0.0 + self._watchdog_thread = None # ✅ 初始化 + self._running = False # ✅ 初始化 + # Windows 隐藏子窗口启动参数 self._si = None if os.name == "nt": @@ -175,37 +178,39 @@ class FlaskSubprocessManager: return False # ========= 停止 ========= - def stop(self): + def stop(self, *, stop_watchdog: bool = True): with self._lock: - if not self.process: return - try: - if self.process.stdout: - self.process.stdout.flush() - time.sleep(0.1) # 让读取线程跟上 - except Exception: - pass - - with self._lock: - if not self.process: - return - pid = self.process.pid - self._log("info", f"[FlaskMgr] 正在停止子进程 PID={pid}") - try: - parent = psutil.Process(pid) - for child in parent.children(recursive=True): + # 1) 先停子进程 + if self.process: + try: + self.process.terminate() + except Exception: + pass + try: + self.process.wait(timeout=3) + except Exception: + pass + if self.process and self.process.poll() is None: try: - child.kill() + self.process.kill() except Exception: pass - parent.kill() - parent.wait(timeout=3) - except psutil.NoSuchProcess: - pass - except Exception as e: - self._log("error", f"[FlaskMgr] 停止子进程异常: {e}") - finally: self.process = None - self._stop_event.set() + + # 2) 再考虑是否停 watchdog + if stop_watchdog and self._watchdog_thread and self._watchdog_thread.is_alive(): + # 关键:不要 join 自己 + if threading.current_thread() is not self._watchdog_thread: + self._running = False + try: + self._watchdog_thread.join(timeout=2.0) + except Exception: + pass + self._watchdog_thread = None + else: + # 如果是 watchdog 自己触发的 stop,绝不 join 自己 + # 也不要把句柄清空,保持线程继续执行后面的重启流程 + self._running = True # ========= 看门狗 ========= def _monitor(self): diff --git a/Module/Main.py b/Module/Main.py index 5be4173..5140b7e 100644 --- a/Module/Main.py +++ b/Module/Main.py @@ -30,6 +30,7 @@ print(f"日志目录: {LOG_DIR}") def _run_flask_role(): from Module import FlaskService + print("Flask Pid:", os.getpid()) port = int(os.getenv("FLASK_COMM_PORT", "34566")) # 固定端口的兜底仍是 34567 app_factory = getattr(FlaskService, "create_app", None) app = app_factory() if callable(app_factory) else FlaskService.app diff --git a/Module/__pycache__/DeviceInfo.cpython-312.pyc b/Module/__pycache__/DeviceInfo.cpython-312.pyc index 3ada30a..f35294f 100644 Binary files a/Module/__pycache__/DeviceInfo.cpython-312.pyc and b/Module/__pycache__/DeviceInfo.cpython-312.pyc differ diff --git a/Module/__pycache__/FlaskService.cpython-312.pyc b/Module/__pycache__/FlaskService.cpython-312.pyc index da3025b..cabc1c7 100644 Binary files a/Module/__pycache__/FlaskService.cpython-312.pyc and b/Module/__pycache__/FlaskService.cpython-312.pyc differ diff --git a/Module/__pycache__/FlaskSubprocessManager.cpython-312.pyc b/Module/__pycache__/FlaskSubprocessManager.cpython-312.pyc index ead2a69..0055aac 100644 Binary files a/Module/__pycache__/FlaskSubprocessManager.cpython-312.pyc and b/Module/__pycache__/FlaskSubprocessManager.cpython-312.pyc differ diff --git a/Utils/__pycache__/LogManager.cpython-312.pyc b/Utils/__pycache__/LogManager.cpython-312.pyc index f3c3b82..af87589 100644 Binary files a/Utils/__pycache__/LogManager.cpython-312.pyc and b/Utils/__pycache__/LogManager.cpython-312.pyc differ