加固flask看门狗

This commit is contained in:
2025-11-06 21:50:28 +08:00
parent 972c2d0d97
commit 9ed5602b86
6 changed files with 33 additions and 27 deletions

View File

@@ -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):

View File

@@ -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