fix: price_monitor自愈式单例守卫(进程堆积事故)

- cron每2分钟拉起+外网抖动挂起+timeout仅SIGTERM杀不动 → 5并发烧155%CPU
- 新鲜实例在跑则退出(防堆积); 卡死>300s则SIGKILL接管(自愈)
- 符合进程生命周期铁律(防重复启动+卡死检测+自动清理)
This commit is contained in:
xxm
2026-08-05 14:57:10 +08:00
parent 649d52071a
commit 7da799d4db
+38
View File
@@ -818,8 +818,46 @@ def run_once(round_label=""):
pass
def _singleton_guard(max_age_sec=300):
"""自愈式单例守卫(2026-08-05 进程堆积事故修复)
背景:cron每2分钟拉起本脚本,外网抖动时实例挂起不退,timeout(仅SIGTERM)杀不动,
5个并发烧~155% CPU。规则:
- 有其他"新鲜"实例(存活<max_age)在跑 → 本实例立即退出(防堆积)
- 有"卡死"实例(存活>max_age)→ SIGKILL 接管(自愈)
"""
import subprocess as _sp, os as _os, sys as _sys
my_pid = _os.getpid()
try:
out = _sp.run(["ps", "-C", "python3", "-o", "pid,etimes,cmd"],
capture_output=True, text=True, timeout=10).stdout
for line in out.splitlines():
if "price_monitor.py" not in line:
continue
parts = line.split(None, 2)
if len(parts) < 3:
continue
try:
pid = int(parts[0]); age = int(parts[1])
except ValueError:
continue
if pid == my_pid:
continue
if age > max_age_sec:
try:
_os.kill(pid, 9)
print(f"[guard] SIGKILL卡死实例 pid={pid} age={age}s", flush=True)
except ProcessLookupError:
pass
else:
print(f"[guard] 已有新鲜实例 pid={pid} age={age}s 在跑, 本实例退出", flush=True)
_sys.exit(0)
except Exception as _e:
print(f"[guard] 守卫异常(放行): {_e}", flush=True)
def main():
"""每cron触发跑一轮"""
_singleton_guard(max_age_sec=300)
run_once()