Skip to content

[问题] Docker/NAS 部署下 Web server 子进程退出后 /tmp/webserver.pid 残留,导致 start_webserver 误判为已运行 #957

@slashinchi

Description

@slashinchi

📦 TrendRadar 版本

v6.0.0

🔌 MCP Server 版本 (可选)

No response

🏷️ 问题类别

部署运行相关(Docker、Actions、Python 报错)

🤖 AI 模型名称(AI 问题必填)

No response

📝 描述发生了什么

📦 TrendRadar 版本

v6.0.0

🔌 MCP Server 版本 (可选)

No response

🏷️ 问题类别

Docker / Web 页面访问相关

📝 描述发生了什么

在 NAS 上通过 Docker 部署 TrendRadar,并启用了内置 Web 服务器用于访问 output 目录下的 HTML 报告。

最初一段时间可以通过 NAS_IP:WEBSERVER_PORT 正常访问页面,但运行一段时间后会出现下面的情况:

  1. 浏览器访问 http://NAS_IP:WEBSERVER_PORT 失败,表现为 ERR_CONNECTION_REFUSED
  2. 容器日志中仍然会提示:
    • 🌐 启动 Web 服务器...
    • ⚠️ Web 服务器已在运行 (PID: xxx)
  3. 但容器内记录的 /tmp/webserver.pid 对应的进程实际上已经不存在
  4. 此时不会自动恢复,必须手工删除 PID 文件并重新执行 python manage.py start_webserver 才能恢复访问

📋 关键验证结果

故障发生时,容器内检查结果如下:

cat /tmp/webserver.pid
``` {data-source-line="41"}

输出示例:

```text
19
``` {data-source-line="47"}

继续检查对应进程:

```bash
cat /proc/19/cmdline
``` {data-source-line="53"}

输出:

```text
cat: /proc/19/cmdline: No such file or directory
``` {data-source-line="59"}

说明 `/tmp/webserver.pid` 记录的 PID 已失效,但 PID 文件仍然保留。

手工恢复命令如下:

```bash
docker exec trendradar sh -lc 'rm -f /tmp/webserver.pid'
docker exec trendradar python manage.py start_webserver
``` {data-source-line="68"}

恢复后验证:

```bash
curl -I http://127.0.0.1:54808
curl -I http://192.168.1.200:54808
docker exec trendradar python manage.py webserver_status
``` {data-source-line="76"}

恢复结果:

- `127.0.0.1:54808` 返回 `HTTP/1.0 200 OK`
- `NAS_IP:54808` 返回 `HTTP/1.0 200 OK`
- `webserver_status` 显示 `运行中`

### 🔄 可复现链路

可以通过以下步骤稳定复现“服务停止后 watchdog 缺失、PID 残留导致无法自恢复”的问题:

1. 启动 TrendRadar,确认 Web 页面可访问
2. 执行:

```bash
docker exec trendradar python manage.py stop_webserver
``` {data-source-line="93"}

3. 此时访问页面失败
4. 再执行:

```bash
docker exec trendradar python manage.py start_webserver
``` {data-source-line="100"}

在某些情况下,日志会提示“Web 服务器已在运行”,但实际访问仍失败
5. 检查 `/tmp/webserver.pid`,会发现对应进程已不存在

### 🖥️ 使用环境

Docker (本地/NAS)

### ⚙️ 相关配置

- `ENABLE_WEBSERVER=true`
- `WEBSERVER_PORT=54808`
- `docker-compose.yml` 中端口映射为:

```yaml
ports:
  - "${WEBSERVER_PORT}:${WEBSERVER_PORT}"
``` {data-source-line="118"}

### 🔍 代码层面的判断

当前仓库中:

- `docker/manage.py``start_webserver()``webserver_status()` 主要依赖 `/tmp/webserver.pid``os.kill(pid, 0)` 判断进程状态
- `docker/entrypoint.sh` 只在容器启动时拉起一次 Web server,没有持续健康检查或自愈逻辑

如果 Web server 子进程异常退出,而 PID 文件没有及时清理,就会出现:

1. 服务已不可用
2. PID 文件仍存在
3. `start_webserver` 误判为“已在运行”
4. 页面持续无法访问,直到手工恢复

### ✅ 期望行为

希望项目增加更稳健的处理方式,例如:

1. `start_webserver()` 不仅检查 PID 是否存在,还验证:
   - `/proc/<pid>` 是否存在
   - 对应命令是否真的是 `http.server`
   - 本地 HTTP 探活是否成功
2. 当发现 PID 文件失效时,自动清理 stale PID
3. 容器运行期间增加轻量的 Web server 自愈机制,避免子进程退出后只能手工恢复

### 🛠️ 当前 workaround

目前我在宿主机加了一个 Bash watchdog 定时任务,每 15 分钟检查一次:

1. `curl http://127.0.0.1:${WEBSERVER_PORT}/index.html`
2. 如果失败:
   - 删除 `/tmp/webserver.pid`
   - 执行 `python manage.py start_webserver`
3. 再次探活确认恢复

这个 workaround 已验证有效,但我认为根因仍应该由项目本身修复。

### 📎 相关 issue

我查到的相关 issue 主要是端口配置或访问症状相似,但根因不同:

- #757 启动后不能通过浏览器访问查看最新报告
- #748 端口被占用了,如何在 compose 文件中修改

这两个 issue 更偏向端口映射或 `.env` 配置问题,不是这次的 stale PID / 无自愈问题。

### 📋 错误日志/配置(可选)

_No response_

### 📷 截图(强烈建议)

_No response_

### 🖥️ 使用环境

Docker (本地/NAS)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions