fix: 修复内存泄漏和僵尸进程问题

- 添加SIGCHLD信号处理器自动回收僵尸子进程
- 定期清理函数增加僵尸进程回收
- 增加batch_task_screenshots超时清理(30分钟)
- 增加pending_random_schedules超时清理(2小时)
- 修复playwright_automation.py的_force_cleanup使用SIGTERM+waitpid
- browser_installer.py浏览器检测后添加僵尸进程清理

内存占用从111MB降至53MB,僵尸进程从6个降至0个
This commit is contained in:
Yu Yon
2025-12-12 23:42:30 +08:00
parent 352c61fbd4
commit b905739515
3 changed files with 81 additions and 1 deletions

58
app.py
View File

@@ -14,6 +14,24 @@ try:
except AttributeError:
pass # Windows系统不支持tzset()
# 设置SIGCHLD信号处理器自动回收僵尸子进程Docker PID 1 问题)
import signal
def _sigchld_handler(signum, frame):
"""SIGCHLD信号处理器 - 自动回收僵尸子进程"""
while True:
try:
pid, status = os.waitpid(-1, os.WNOHANG)
if pid == 0:
break
except ChildProcessError:
break
except Exception:
break
# 只在Linux上设置Docker环境
if os.name != 'nt':
signal.signal(signal.SIGCHLD, _sigchld_handler)
import pytz
from datetime import datetime
from flask import Flask, render_template, request, jsonify, send_from_directory, redirect, url_for, session
@@ -255,6 +273,46 @@ def cleanup_expired_data():
if completed_tasks:
logger.debug(f"已清理 {len(completed_tasks)} 个已完成任务状态")
# 5. 清理僵尸进程防止Chrome子进程变成僵尸
try:
import os
import signal
# 回收所有已终止的子进程
while True:
try:
pid, status = os.waitpid(-1, os.WNOHANG)
if pid == 0:
break
logger.debug(f"已回收僵尸进程: PID={pid}")
except ChildProcessError:
break # 没有子进程了
except Exception as e:
pass # 忽略清理错误
# 6. 清理超时的批量截图任务超过30分钟未完成的
with batch_task_lock:
expired_batches = []
for batch_id, batch_data in list(batch_task_screenshots.items()):
created_time = batch_data.get('created_time', 0)
if created_time and (current_time - created_time) > 1800: # 30分钟
expired_batches.append(batch_id)
for batch_id in expired_batches:
del batch_task_screenshots[batch_id]
if expired_batches:
logger.debug(f"已清理 {len(expired_batches)} 个超时批量截图任务")
# 7. 清理过期的随机延迟任务超过2小时未执行的
with pending_random_lock:
expired_schedules = []
for schedule_id, schedule_data in list(pending_random_schedules.items()):
created_time = schedule_data.get('created_time', 0)
if created_time and (current_time - created_time) > 7200: # 2小时
expired_schedules.append(schedule_id)
for schedule_id in expired_schedules:
del pending_random_schedules[schedule_id]
if expired_schedules:
logger.debug(f"已清理 {len(expired_schedules)} 个过期随机延迟任务")
def start_cleanup_scheduler():
"""启动定期清理调度器"""