mirror of
https://github.com/GuDong2003/xianyu-auto-reply-fix.git
synced 2026-08-28 17:40:45 +08:00
4749e02088
* fix(滑块): 修复强杀兜底静默失效导致的浏览器进程泄漏 Python sync API 的 Browser/Context 对象并不暴露 process 属性, _extract_browser_pid 两条提取路径实际永远返回 None,导致 _force_kill_browser_process_tree 在所有调用点都是静默空操作。 浏览器 close/stop 挂死或跨线程被跳过时,node driver + chrome 进程树无人回收,长期累积耗尽内存和 CPU(实测 2 天泄漏 3 组 会话、36 个 chrome 进程,swap 占满、负载冲到 11+)。 修复: - _extract_browser_pid 增加回退路径:从 Playwright driver 的 PipeTransport 子进程句柄提取 PID(chrome 全部挂在 driver 之下, 按 driver 进程树清理等效覆盖浏览器进程树) - close_browser 增加 20 秒看门狗:优雅清理挂死(如页面死循环时 close() 同线程永久阻塞)时强杀进程树解锁流程 - docker-compose 增加 init: true,回收 chrome 退出后的僵尸进程 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(账号管理): 修复残留任务引用导致账号任务永久假死 登录/验证成功后新账号任务启动与状态置"启用"存在竞态:任务启动 瞬间若读到旧的"禁用"状态会立即退出,但 self.tasks 中的引用不会 被清理;之后置"启用"触发 _start_cookie_task 时因引用存在被 "任务已存在"跳过,账号从此永远无法连接(实测复现:人脸验证成功、 Cookie 已入库,但账号任务假死,界面持续显示未登录)。 修复:_start_cookie_task 检查已存在任务的 done() 状态, 已结束的残留引用先清理再正常启动。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(验证): 验证完成后回填风控日志状态,截图接口不再误报待验证 两个叠加问题导致人脸/扫码验证成功后,前端"查看验证截图"仍持续 展示历史截图、看起来像验证没有生效: 1. face_verify 等验证类风控日志在检测阶段写入 processing 状态, 验证成功后只新增 cookie_refresh 成功日志,从不回填原日志, 数据库中留下永远 processing 的验证记录 2. /face-verification/screenshot 接口只处理了 verification_required (返回截图)和 failed+超时(提示失效)两种状态,验证已成功时 落到 glob 兜底,把留档的历史截图当成待处理验证返回 修复: - db_manager 新增 resolve_pending_verification_risk_logs:按账号 批量将悬挂在 processing/pending 的验证类日志置为 success - _finalize_logged_in_cookies 成功收尾时调用回填 - 截图接口对最新验证日志为 success 的情况返回"当前没有待处理的 验证",不再展示历史截图 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(滑块): 补齐 urlencode/quote_plus 缺失导入 _build_login_probe_requests 使用了 urlencode 和 quote_plus,但 urllib.parse 只导入了 parse_qs 和 urlparse。人脸验证成功后的 Cookie 探测链路执行到此处即抛 NameError: 密码登录流程异常: name 'urlencode' is not defined 导致验证已成功、Cookie 已到手的恢复流程整体失败,账号被错误 标记为"待人脸验证"并暂停,用户反复完成人脸验证也无法登录。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(滑块): PID 提取兼容 asyncio.subprocess.Process;看门狗取消移入 finally 评审意见修复: 1. sync API 下 _connection._transport._proc 实际是 asyncio.subprocess.Process(实测确认),只有 returncode 没有 poll(),原实现会抛 AttributeError 被外层吞掉、回退路径永远 返回 None。改为兼容 poll() 和 returncode 两种存活判断,并把 属性链访问全部改为 getattr 防御式写法。 2. close_browser 的 close_watchdog.cancel() 移入覆盖整个清理 流程的 finally,避免清理中途抛出未捕获异常时看门狗在 20 秒后 按已过期的 _browser_pid 误杀后续新会话的进程树。 容器内实测:修复后回退路径成功提取 driver PID(alive 判断正确), 按进程树 kill 后 driver 进程确认退出。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
129 lines
4.6 KiB
YAML
129 lines
4.6 KiB
YAML
services:
|
|
xianyu-app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
args:
|
|
BASE_IMAGE: python:3.11-slim-bookworm
|
|
HTTP_PROXY: ${HTTP_PROXY}
|
|
HTTPS_PROXY: ${HTTPS_PROXY}
|
|
NO_PROXY: ${NO_PROXY}
|
|
http_proxy: ${HTTP_PROXY}
|
|
https_proxy: ${HTTPS_PROXY}
|
|
no_proxy: ${NO_PROXY}
|
|
image: ghcr.io/gudong2003/xianyu-auto-reply-fix:latest
|
|
container_name: xianyu-auto-reply-fix
|
|
restart: unless-stopped
|
|
# 内置 init 进程回收僵尸进程(chrome 子进程退出后无人 reap 会变 defunct,长期累积)
|
|
init: true
|
|
# 使用root用户避免权限问题
|
|
user: "0:0"
|
|
# 使用 bash 执行脚本,避免 Windows 行尾格式问题
|
|
# 即使挂载了 Windows 文件,bash 也能正确处理
|
|
entrypoint: ["/bin/bash", "-c", "dos2unix /app/entrypoint.sh 2>/dev/null || true; bash /app/entrypoint.sh"]
|
|
ports:
|
|
- "9000:8090"
|
|
- "5900:5900" # VNC 端口(可选,用于远程查看浏览器)
|
|
- "6080:6080" # noVNC Web 端口(浏览器手动接管)
|
|
volumes:
|
|
# 数据持久化
|
|
- ./data:/app/data:rw
|
|
- ./logs:/app/logs:rw
|
|
- ./global_config.yml:/app/global_config.yml:ro
|
|
# 可选:如果需要自定义配置
|
|
# - ./custom_config.yml:/app/global_config.yml:ro
|
|
# 可选:备份目录
|
|
- ./backups:/app/backups:rw
|
|
# 开发模式:挂载源代码(修改代码后只需重启容器)
|
|
- .:/app:rw
|
|
environment:
|
|
# 启用虚拟显示(有头模式)
|
|
- USE_XVFB=true # 启用 Xvfb 虚拟显示
|
|
- ENABLE_HEADFUL=true # 启用有头模式
|
|
- ENABLE_VNC=true # 启用 VNC 服务器(可选)
|
|
- DISPLAY=:99 # 虚拟显示编号
|
|
|
|
- PYTHONUNBUFFERED=${PYTHONUNBUFFERED:-1}
|
|
- PYTHONDONTWRITEBYTECODE=${PYTHONDONTWRITEBYTECODE:-1}
|
|
- TZ=${TZ:-Asia/Shanghai}
|
|
- DB_PATH=${DB_PATH:-/app/data/xianyu_data.db}
|
|
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
|
- DEBUG=${DEBUG:-false}
|
|
- RELOAD=${RELOAD:-false}
|
|
# SQL日志配置(默认启用,可通过环境变量覆盖)
|
|
- SQL_LOG_ENABLED=${SQL_LOG_ENABLED:-true}
|
|
- SQL_LOG_LEVEL=${SQL_LOG_LEVEL:-INFO}
|
|
- ADMIN_USERNAME=${ADMIN_USERNAME:-admin}
|
|
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123}
|
|
- JWT_SECRET_KEY=${JWT_SECRET_KEY:-default-secret-key}
|
|
- SESSION_TIMEOUT=${SESSION_TIMEOUT:-3600}
|
|
# 多用户系统配置
|
|
- MULTIUSER_ENABLED=${MULTIUSER_ENABLED:-true}
|
|
- USER_REGISTRATION_ENABLED=${USER_REGISTRATION_ENABLED:-true}
|
|
- EMAIL_VERIFICATION_ENABLED=${EMAIL_VERIFICATION_ENABLED:-true}
|
|
- CAPTCHA_ENABLED=${CAPTCHA_ENABLED:-true}
|
|
- TOKEN_EXPIRE_TIME=${TOKEN_EXPIRE_TIME:-86400}
|
|
- AUTO_REPLY_ENABLED=${AUTO_REPLY_ENABLED:-true}
|
|
- AUTO_DELIVERY_ENABLED=${AUTO_DELIVERY_ENABLED:-true}
|
|
- AUTO_DELIVERY_TIMEOUT=${AUTO_DELIVERY_TIMEOUT:-30}
|
|
- API_CARD_TIMEOUT=${API_CARD_TIMEOUT:-10}
|
|
- BATCH_DATA_LOCK_TIMEOUT=${BATCH_DATA_LOCK_TIMEOUT:-5}
|
|
# AI回复相关配置
|
|
- AI_REPLY_ENABLED=${AI_REPLY_ENABLED:-false}
|
|
- DEFAULT_AI_MODEL=${DEFAULT_AI_MODEL:-qwen-plus}
|
|
- DEFAULT_AI_BASE_URL=${DEFAULT_AI_BASE_URL:-https://dashscope.aliyuncs.com/compatible-mode/v1}
|
|
- AI_REQUEST_TIMEOUT=${AI_REQUEST_TIMEOUT:-30}
|
|
- AI_MAX_TOKENS=${AI_MAX_TOKENS:-100}
|
|
- WEBSOCKET_URL=${WEBSOCKET_URL:-wss://wss-goofish.dingtalk.com/}
|
|
- HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-15}
|
|
- HEARTBEAT_TIMEOUT=${HEARTBEAT_TIMEOUT:-5}
|
|
- TOKEN_REFRESH_INTERVAL=${TOKEN_REFRESH_INTERVAL:-3600}
|
|
- TOKEN_RETRY_INTERVAL=${TOKEN_RETRY_INTERVAL:-300}
|
|
- MESSAGE_EXPIRE_TIME=${MESSAGE_EXPIRE_TIME:-300000}
|
|
|
|
networks:
|
|
- xianyu-network
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-f", "http://localhost:8090/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 40s
|
|
# 资源限制
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: ${MEMORY_LIMIT:-2048}M
|
|
cpus: '${CPU_LIMIT:-2.0}'
|
|
reservations:
|
|
memory: ${MEMORY_RESERVATION:-512}M
|
|
cpus: '${CPU_RESERVATION:-0.5}'
|
|
|
|
# 可选:添加Nginx反向代理
|
|
nginx:
|
|
image: nginx:alpine
|
|
container_name: xianyu-nginx
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
- ./nginx/ssl:/etc/nginx/ssl:ro
|
|
depends_on:
|
|
- xianyu-app
|
|
networks:
|
|
- xianyu-network
|
|
profiles:
|
|
- with-nginx
|
|
|
|
networks:
|
|
xianyu-network:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
xianyu-data:
|
|
driver: local
|
|
xianyu-logs:
|
|
driver: local
|