# PM2 ↺ 阈值告警部署

> 工单 #249【1】的运维侧落地说明。脚本本体：`scripts/ops/pm2-restart-watch.sh`。
> 拦元根因 5（监控告警缺失），详见 [`docs/standards/12-five-meta-rules.md` 规则 5](../standards/12-five-meta-rules.md)。

## 背景

PM2 进程异常 ↺（Out-of-Memory / 启动失败循环 / 依赖断）当前**无任何自动告警**——[工单 #242](http://43.130.59.228/FFAIWorkspace/workspace/issues/242) 期间 backend ↺=23 持续 9 天没人发现，直到用户报错。

本脚本周期性抓 `pm2 jlist` 比较 ↺ 增量，超阈值发钉钉/飞书 webhook 告警。

## 部署目标

4 台业务主机：UAT × 2、PROD × 2（具体清单见 `docs/ops/01-server-infrastructure.md`）。

## 配置项

| Env | 必填 | 默认 | 说明 |
|---|---|---|---|
| `OPS_WEBHOOK_URL` | ✅ | — | 钉钉或飞书 incoming webhook URL |
| `OPS_WEBHOOK_TYPE` | — | 自适应 | `dingtalk` / `feishu`，缺省按 URL 域名判断 |
| `PM2_RESTART_THRESHOLD` | — | `100` | 单进程窗口内 ↺ 增长触发阈值 |
| `PM2_RESTART_WINDOW_SECS` | — | `3600` | 时间窗口（秒），默认 1h |
| `PM2_RESTART_STATE_DIR` | — | `~/.cache/pm2-restart-watch` | state file 目录 |

## 部署步骤（每台机器）

1. **创建 webhook 机器人**（钉钉群"群设置 → 智能群助手 → 添加机器人 → 自定义"，或飞书"群设置 → 群机器人 → 添加机器人 → 自定义机器人"），拿到 webhook URL。
2. **写入 env**（推荐用 systemd EnvironmentFile，避免硬编码到 crontab）：
   ```bash
   sudo tee /etc/default/pm2-restart-watch <<EOF
   OPS_WEBHOOK_URL=https://oapi.dingtalk.com/robot/send?access_token=xxxxx
   PM2_RESTART_THRESHOLD=100
   EOF
   sudo chmod 600 /etc/default/pm2-restart-watch
   ```
3. **self-check 验证**（实测完工，对应规则 4）：
   ```bash
   set -a; source /etc/default/pm2-restart-watch; set +a
   bash /srv/apps/ffoa/scripts/ops/pm2-restart-watch.sh --self-check
   ```
   预期：`✅ webhook 可达且配置正确（body errcode=0）`，且 webhook 群里收到一条 `[self-check] hostname at <ts>` 测试消息。
4. **加 cron**（每 10 分钟跑一次）：
   ```bash
   crontab -e
   # 加入：
   */10 * * * * set -a; . /etc/default/pm2-restart-watch; set +a; /srv/apps/ffoa/scripts/ops/pm2-restart-watch.sh >> /var/log/pm2-restart-watch.log 2>&1
   ```
5. **观察 24h**：日志 `/var/log/pm2-restart-watch.log` 应出现规律记录，群里**不应有告警**（说明基线正常）。

## 验收（必须真实演练，对应规则 5）

部署后 1 周内，主动制造一次 ↺ 触发告警：

```bash
# 选一个非关键进程（如 worker），临时降阈值到 5，然后手工抖几次
PM2_RESTART_THRESHOLD=5 /srv/apps/ffoa/scripts/ops/pm2-restart-watch.sh --dry-run
pm2 restart <non-critical-proc>
pm2 restart <non-critical-proc>
pm2 restart <non-critical-proc>
pm2 restart <non-critical-proc>
pm2 restart <non-critical-proc>
PM2_RESTART_THRESHOLD=5 /srv/apps/ffoa/scripts/ops/pm2-restart-watch.sh
# 预期：webhook 群里收到告警，含 hostname / 进程名 / ↺ 增量 / 最近 stderr 摘要
```

未演练 = 未真正完工（规则 4：完工 = 实测业务行为）。

## 故障排查

- **告警从未触发但进程明显 ↺**：检查 `state.json` 是否被异常重置；windows 设大于实际 ↺ 间隔
- **告警刷屏**：阈值偏低，或某进程长期不稳定 → 拉高阈值 + 单独排查该进程
- **webhook 群无消息**：跑 `--self-check` 验配置；检查 cron 日志 `/var/log/pm2-restart-watch.log`

## 关联

- 脚本本体：[`scripts/ops/pm2-restart-watch.sh`](../../scripts/ops/pm2-restart-watch.sh)
- 规则文档：[`docs/standards/12-five-meta-rules.md`](../standards/12-five-meta-rules.md) 规则 5
- 后续：工单 #249【5】Healthcheck 加严（业务可用性，不止 ↺ 计数）
