248 lines
4.5 KiB
Markdown
248 lines
4.5 KiB
Markdown
# 服务崩溃问题分析报告
|
||||
|
|
|
|||
|
|
## 问题现象
|
|||
|
|
- 时间: 2026-02-24 16:14
|
|||
|
|
- 症状: 服务无响应 ERR_EMPTY_RESPONSE
|
|||
|
|
- 频率: 已发生2次(14:55, 16:14)
|
|||
|
|
|
|||
|
|
## 根本原因分析
|
|||
|
|
|
|||
|
|
### 1. 缺少异常处理机制 (严重) 🔴
|
|||
|
|
|
|||
|
|
**问题代码**:
|
|||
|
|
```javascript
|
|||
|
|
// server.js 无全局异常捕获
|
|||
|
|
app.listen(PORT, () => { ... });
|
|||
|
|
|
|||
|
|
// 所有API路由无错误处理
|
|||
|
|
app.get('/api/stats', (req, res) => {
|
|||
|
|
db.get('SELECT ...', (err, result) => {
|
|||
|
|
// err未处理,直接使用result
|
|||
|
|
res.json(result);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**风险**:
|
|||
|
|
- 未捕获异常导致进程崩溃
|
|||
|
|
- 数据库错误导致服务器退出
|
|||
|
|
- 客户端请求错误无响应
|
|||
|
|
|
|||
|
|
**影响**: 任何未预期的错误都会导致整个服务崩溃
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 进程管理缺失 (严重) 🔴
|
|||
|
|
|
|||
|
|
**当前启动方式**:
|
|||
|
|
```bash
|
|||
|
|
node server.js > server.log 2>&1 &
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
- ❌ 没有进程守护
|
|||
|
|
- ❌ 没有自动重启
|
|||
|
|
- ❌ 依赖shell会话(可能被终端关闭影响)
|
|||
|
|
- ❌ 没有进程监控
|
|||
|
|
|
|||
|
|
**对比专业方案**:
|
|||
|
|
```bash
|
|||
|
|
# 应该使用 PM2
|
|||
|
|
pm2 start server.js --name task-service
|
|||
|
|
pm2 startup # 开机自启
|
|||
|
|
pm2 save # 保存配置
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 数据库连接未处理超时 (中等) 🟡
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
```javascript
|
|||
|
|
const db = new sqlite3.Database('./tasks.db', (err) => {
|
|||
|
|
if (err) {
|
|||
|
|
process.exit(1); // 直接退出
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
// 没有连接保活机制
|
|||
|
|
// 没有重连机制
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**风险**:
|
|||
|
|
- 数据库文件锁定导致连接失败
|
|||
|
|
- 长时间运行后可能连接失效
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 4. 端口冲突无处理 (中等) 🟡
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
```javascript
|
|||
|
|
app.listen(PORT, () => { ... });
|
|||
|
|
// 没有监听 'error' 事件
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**可能情况**:
|
|||
|
|
```
|
|||
|
|
端口3000被占用 → listen失败 → 无错误提示 → 服务看似启动实际未运行
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 5. 配置文件不匹配 (轻微) 🟢
|
|||
|
|
|
|||
|
|
**package.json**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"main": "server-postgres.js", // ❌ 文件已删除
|
|||
|
|
"scripts": {
|
|||
|
|
"start": "node server-postgres.js" // ❌ 错误
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**影响**: npm start 无法运行
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 推荐修复方案(优先级排序)
|
|||
|
|
|
|||
|
|
### 🔴 P0 - 立即修复(必须)
|
|||
|
|
|
|||
|
|
#### 1. 添加全局异常处理
|
|||
|
|
```javascript
|
|||
|
|
// server.js 底部添加
|
|||
|
|
process.on('uncaughtException', (err) => {
|
|||
|
|
console.error('❌ 未捕获异常:', err);
|
|||
|
|
// 不退出,记录日志继续运行
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|||
|
|
console.error('❌ 未处理的Promise拒绝:', reason);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 监听端口错误
|
|||
|
|
const server = app.listen(PORT, () => { ... });
|
|||
|
|
server.on('error', (err) => {
|
|||
|
|
if (err.code === 'EADDRINUSE') {
|
|||
|
|
console.error(`❌ 端口 ${PORT} 已被占用`);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 2. 添加API错误处理中间件
|
|||
|
|
```javascript
|
|||
|
|
// 所有路由后添加
|
|||
|
|
app.use((err, req, res, next) => {
|
|||
|
|
console.error('API错误:', err);
|
|||
|
|
res.status(500).json({ error: err.message });
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3. 使用PM2管理进程
|
|||
|
|
```bash
|
|||
|
|
npm install -g pm2
|
|||
|
|
pm2 start server.js --name task-service
|
|||
|
|
pm2 startup
|
|||
|
|
pm2 save
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🟡 P1 - 重要优化(建议)
|
|||
|
|
|
|||
|
|
#### 4. 数据库查询添加try-catch
|
|||
|
|
```javascript
|
|||
|
|
app.get('/api/stats', async (req, res) => {
|
|||
|
|
try {
|
|||
|
|
db.get('SELECT ...', (err, result) => {
|
|||
|
|
if (err) {
|
|||
|
|
return res.status(500).json({ error: err.message });
|
|||
|
|
}
|
|||
|
|
res.json(result);
|
|||
|
|
});
|
|||
|
|
} catch (error) {
|
|||
|
|
res.status(500).json({ error: error.message });
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5. 添加健康检查端点
|
|||
|
|
```javascript
|
|||
|
|
app.get('/health', (req, res) => {
|
|||
|
|
res.json({ status: 'ok', timestamp: new Date() });
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🟢 P2 - 长期改进(可选)
|
|||
|
|
|
|||
|
|
#### 6. 日志系统升级
|
|||
|
|
```javascript
|
|||
|
|
const winston = require('winston');
|
|||
|
|
// 结构化日志,自动轮转
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 7. 监控告警
|
|||
|
|
```javascript
|
|||
|
|
// 性能监控
|
|||
|
|
// 崩溃告警
|
|||
|
|
// 自动重启通知
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 临时解决方案(当前使用)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. 检查端口
|
|||
|
|
lsof -i :3000
|
|||
|
|
|
|||
|
|
# 2. 杀死占用进程
|
|||
|
|
pkill -f "node server"
|
|||
|
|
|
|||
|
|
# 3. 重启服务
|
|||
|
|
cd /data/openclaw/workspace/agent-task-service
|
|||
|
|
node server.js > server.log 2>&1 &
|
|||
|
|
|
|||
|
|
# 4. 验证
|
|||
|
|
curl http://localhost:3000/api/stats
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**缺点**: 不解决根本问题,随时可能再次崩溃
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 建议执行顺序
|
|||
|
|
|
|||
|
|
1. **立即** - 修复server.js添加异常处理
|
|||
|
|
2. **立即** - 安装并配置PM2
|
|||
|
|
3. **今天** - 添加API错误处理
|
|||
|
|
4. **本周** - 完善日志和监控
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 测试验证
|
|||
|
|
|
|||
|
|
修复后需验证:
|
|||
|
|
```bash
|
|||
|
|
# 1. 模拟崩溃
|
|||
|
|
curl http://localhost:3000/api/nonexist
|
|||
|
|
|
|||
|
|
# 2. 检查进程存活
|
|||
|
|
pm2 status
|
|||
|
|
|
|||
|
|
# 3. 查看日志
|
|||
|
|
pm2 logs task-service
|
|||
|
|
|
|||
|
|
# 4. 压力测试
|
|||
|
|
ab -n 1000 -c 10 http://localhost:3000/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
生成时间: 2026-02-24 16:20
|
|||
|
|
优先级: P0 (生产环境严重问题)
|