From 9ed5602b86cc9119a6e7622235348da8c67281b0 Mon Sep 17 00:00:00 2001 From: milk <53408947@qq.com> Date: Thu, 6 Nov 2025 21:50:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=9B=BAflask=E7=9C=8B=E9=97=A8?= =?UTF-8?q?=E7=8B=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Module/FlaskSubprocessManager.py | 59 ++++++++++-------- Module/Main.py | 1 + Module/__pycache__/DeviceInfo.cpython-312.pyc | Bin 42543 -> 42543 bytes .../__pycache__/FlaskService.cpython-312.pyc | Bin 42578 -> 42578 bytes .../FlaskSubprocessManager.cpython-312.pyc | Bin 17701 -> 17279 bytes Utils/__pycache__/LogManager.cpython-312.pyc | Bin 14663 -> 14663 bytes 6 files changed, 33 insertions(+), 27 deletions(-) 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 3ada30a723c45167fd6e7d8ec4fe970e6d98938a..f35294f61a1054ca57f854228cb7b0f6ca8d6d45 100644 GIT binary patch delta 22 ccmZ2~hH3p7ChpU`yj%=Ga3+>#Be%*j09CjKumAu6 delta 22 ccmZ2~hH3p7ChpU`yj%=GQ0>CKky~XM08-`#MF0Q* diff --git a/Module/__pycache__/FlaskService.cpython-312.pyc b/Module/__pycache__/FlaskService.cpython-312.pyc index da3025bf7872182e30a0e95770dc3dcb17d966c2..cabc1c76079b459f5fe0397782c3f0811a31f0cd 100644 GIT binary patch delta 22 ccmca~hUwB7ChpU`yj%=GAUlI+Be(l909Y~xr2qf` delta 22 ccmca~hUwB7ChpU`yj%=GU}MI;k=uP409LvNVE_OC diff --git a/Module/__pycache__/FlaskSubprocessManager.cpython-312.pyc b/Module/__pycache__/FlaskSubprocessManager.cpython-312.pyc index ead2a69a53c535a07fe529a64ae9b50142ba4f6b..0055aac5a7b160b1de0653c6e5b361f7fb337852 100644 GIT binary patch delta 2721 zcmaJ@eQZBFztzBEKJLfr` z=qmNf{@r_j=iGD8z31L@-}6tB&%R6Szqi@SIVeAR!5UZZJ8l1rtS~!ylz7=R8G2N% z`T>z0ifgYyu0AGAx@G4vZqg&$bjEdzpA_X9#jE#u*$sW)s>}oJTE#E>Wbqh(2`7Lu z892@zCX>O3IjOebW)E52iw=WoAa5;xho2`wxqOa`R2Nk_PUfKJEcG-yTPOIevo zj-w;2-V|IX{*~AXGe5|U>L6lWj&;hEtUPDwkmQcs>P<{ z^uCBTMU|*rFh^)Mm5QhKu?yxmNi|DY&Q{(IH67=d%z;~C;5dKMwrDIj8-x)sOh=i+ zDmD&aa|mGz!Z3i!1B9SZSQkh8*_bs%1{RanX5KvpOu-(DX0$9-BI&G_$!avrE>`Vm z-43GnEC7;&Hsiofgf4)BH8!Qhrc3JUS)F5(*pC8ZGMXvy)A2-tJ^+1*rvvPOqe19} z&a4Ds601=dNz=?!G!@yKh^o^&7Oy%UHGwg8f_sMqV@b{B3w$r~`7=^J} ziCw9!VXymVd^nHpPoYdn9gNd-s=&w6nHf649tx}_ooqI+m2|P+1RBVCb~~`n^EeDB zRKn)QwMZsSwMaUnq-Y;&47LmUZe`flgF$kDWrO{~Np#c?j(S+6)%kqlI~_!#J`812%YpI`%)fNgIgt4>8!O@@6w z#||_eB!i28Z~PCj97Ox1oKCTSHh00HXl$9S*4J6uM3B?x*o!Tj$VK*#mVb4QOQc{^ zwRGlxXNJBAIxzx(1#1ERM)-g57I<=&-C4Vyr$;Ot%dGXVx4ljlYAt75*Lqo5hs#EO zX1KIEmY{~)K)ZECyQ`KzQoA~8sUc9U-=)$t+#I1Z>~s^TC$VD7Hot*B%od~|3)#)A z+vRp;30)@};mTBiFM0uMIAp&U?uE0JzjtcgdRa*^RVJJ68OTnzx|6sny)<#uNVo~^ zvY#s(DG+`5x{k#b}NGt>^_eG%new9qAxI z!2)L_8Bax_!q^pfJaz>>lZG4d2x{Gra0(#=09P+dsglxGuRQHQlHZ?>r%Gq38Uy>e z!_)^C*gucae+5O`AR0%wTQ>+52BX7!%O##2J3W?nwdP!{ zORjax!o6g3&eeP|dc)Pc;8Z0;}5%5?Mff3XJA*KvW@tR&-%ha!>j&qyWvW83-qsS^o9EkzjbbLkND<|S6lrf z6^3g*V0)v^_ghBHrt2o;ua^;Qn~}d> zVHxq5uDf*JO|b3Jd7o*d5#9^%Y_+iW*OV_V-2ZREL|+1mJ>AnFM4p4oUx1Z}U3TrvVg`B>g$mDt;c|LsTrq z=V$@A**bh0%*k{ruBGX%mp0Dv(goo6b?N2LgZiBtAC-*sBGB}w2zqWLbT4~;V3gR| z`vYnvZh%B+9ai}Cq&C-)H`wgIl75XT)_{AhC(>AH;VHxRA@fMq>%A3_2j z0Tr)0_*r!FDd^0$pp%uKe@DD*&(LFJkX;`7aU;d+sG9^I(3*eyH8+8(ijVCP?%m4j6WQZdiq1ls7t|S5Q<9Jle#nk){pP&sYh&ry zbTQ>rfeLjXOd#k_20pd=3g`)JnGi57QcSA_eos1`&|^k1z!Z1CxC`(x#8F%)MOO>lH}p_nW@@;- xtsrF7tQJocs&)ga_l>3Z?TDtL`xHvesE_vOpAZJw@4`DPck`rXg+tW0@xLUUvg!Z; delta 2855 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 Dx}V}2 diff --git a/Utils/__pycache__/LogManager.cpython-312.pyc b/Utils/__pycache__/LogManager.cpython-312.pyc index f3c3b82e32101c40003af47ba5c87a8902cf0848..af875895eade1efe4dfd697f4a1bc06910889c8e 100644 GIT binary patch delta 20 acmX?Jbi9cBG%qg~0}u#@@NDF^u>=4@VFeKY delta 20 acmX?Jbi9cBG%qg~0}#ZUac|_du>=4^yahf0