加固flask看门狗
This commit is contained in:
@@ -18,7 +18,7 @@ class FlaskSubprocessManager:
|
|||||||
"""Flask 子进程守护 + 看门狗 + 稳定增强"""
|
"""Flask 子进程守护 + 看门狗 + 稳定增强"""
|
||||||
|
|
||||||
_instance: Optional['FlaskSubprocessManager'] = None
|
_instance: Optional['FlaskSubprocessManager'] = None
|
||||||
_lock = threading.Lock()
|
_lock = threading.RLock()
|
||||||
|
|
||||||
def __new__(cls):
|
def __new__(cls):
|
||||||
with cls._lock:
|
with cls._lock:
|
||||||
@@ -42,6 +42,9 @@ class FlaskSubprocessManager:
|
|||||||
self._fail_count = 0
|
self._fail_count = 0
|
||||||
self._last_restart_time = 0.0
|
self._last_restart_time = 0.0
|
||||||
|
|
||||||
|
self._watchdog_thread = None # ✅ 初始化
|
||||||
|
self._running = False # ✅ 初始化
|
||||||
|
|
||||||
# Windows 隐藏子窗口启动参数
|
# Windows 隐藏子窗口启动参数
|
||||||
self._si = None
|
self._si = None
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
@@ -175,37 +178,39 @@ class FlaskSubprocessManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# ========= 停止 =========
|
# ========= 停止 =========
|
||||||
def stop(self):
|
def stop(self, *, stop_watchdog: bool = True):
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if not self.process: return
|
# 1) 先停子进程
|
||||||
try:
|
if self.process:
|
||||||
if self.process.stdout:
|
try:
|
||||||
self.process.stdout.flush()
|
self.process.terminate()
|
||||||
time.sleep(0.1) # 让读取线程跟上
|
except Exception:
|
||||||
except Exception:
|
pass
|
||||||
pass
|
try:
|
||||||
|
self.process.wait(timeout=3)
|
||||||
with self._lock:
|
except Exception:
|
||||||
if not self.process:
|
pass
|
||||||
return
|
if self.process and self.process.poll() is None:
|
||||||
pid = self.process.pid
|
|
||||||
self._log("info", f"[FlaskMgr] 正在停止子进程 PID={pid}")
|
|
||||||
try:
|
|
||||||
parent = psutil.Process(pid)
|
|
||||||
for child in parent.children(recursive=True):
|
|
||||||
try:
|
try:
|
||||||
child.kill()
|
self.process.kill()
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
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.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):
|
def _monitor(self):
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ print(f"日志目录: {LOG_DIR}")
|
|||||||
|
|
||||||
def _run_flask_role():
|
def _run_flask_role():
|
||||||
from Module import FlaskService
|
from Module import FlaskService
|
||||||
|
print("Flask Pid:", os.getpid())
|
||||||
port = int(os.getenv("FLASK_COMM_PORT", "34566")) # 固定端口的兜底仍是 34567
|
port = int(os.getenv("FLASK_COMM_PORT", "34566")) # 固定端口的兜底仍是 34567
|
||||||
app_factory = getattr(FlaskService, "create_app", None)
|
app_factory = getattr(FlaskService, "create_app", None)
|
||||||
app = app_factory() if callable(app_factory) else FlaskService.app
|
app = app_factory() if callable(app_factory) else FlaskService.app
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user