Files
gongxue-base/docs/refactor/crm-worker.md
2026-06-29 04:35:19 +08:00

108 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CRM Webhook Worker
更新时间2026-06-29
`apps/worker` 是后端异步任务进程,当前首个落地任务是 CRM 客资 webhook 推送。API 只负责在客资首绑时写入 `crm_webhook_queue`worker 负责消费到期任务、签名、发送、失败重试和写入 `crm_webhook_log`
## 运行命令
本地单次消费一批任务:
```bash
npm --workspace @tiku-saas/worker run crm:once
```
或使用根脚本测试:
```bash
npm run test:worker:crm
```
生产常驻:
```bash
npm --workspace @tiku-saas/worker run start
```
建议 API 和 worker 作为两个独立进程部署,共用同一个 `DATABASE_URL`
## 配置
环境变量:
```text
WORKER_CRM_BATCH_SIZE=20
WORKER_CRM_POLL_INTERVAL_MS=10000
WORKER_CRM_MAX_ATTEMPTS=5
WORKER_CRM_BACKOFF_SECONDS=5,30,120,600,1800
WORKER_CRM_REQUEST_TIMEOUT_MS=10000
WORKER_CRM_ALLOW_INSECURE_LOCALHOST=false
```
租户后台配置仍走:
```text
PUT /api/crm/config
GET /api/crm/config
GET /api/crm/queue
```
密钥必须写入 `app_private.tenant_secrets`,公共表 `crm_config.secret_ref` 只保留引用,例如:
```text
app_private.tenant_secrets:crm:webhook
```
## Provider
worker 根据队列 payload 的 `provider` 或 webhook URL 自动判断:
| provider | URL 特征 | 行为 |
| --- | --- | --- |
| `generic` | 默认 | POST `{ event: "lead.created", data: ... }` |
| `dingtalk` | `dingtalk.com` | markdown 消息;按钉钉自定义机器人安全设置做 timestamp/sign |
| `feishu` | `feishu.cn` / `larksuite.com` | interactive card按飞书自定义机器人签名做 timestamp/sign |
| `wecom` | `qyapi.weixin.qq.com` / `work.weixin.qq.com` | 企业微信群机器人 markdown 消息 |
官方参考:
- 钉钉开放平台:[自定义机器人安全设置](https://open.dingtalk.com/document/robots/customize-robot-security-settings)`timestamp + "\n" + secret` 做 HMAC-SHA256 后 Base64。
- 飞书开放平台:[自定义机器人签名校验](https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot),使用 timestamp 和 secret 生成签名。
- 企业微信开发者文档:[群机器人配置说明](https://developer.work.weixin.qq.com/document/path/91770),群机器人 webhook 使用 `msgtype` 消息体。
## 队列状态
`crm_webhook_queue.status`
```text
pending -> processing -> sent
pending -> processing -> retrying -> processing -> sent
pending -> processing -> retrying -> failed
pending -> discarded
```
说明:
- `pending` / `retrying`:等待 worker 消费。
- `processing`worker 已抢占任务。
- `sent`:目标 webhook 返回 2xx。
- `failed`:超过最大重试次数。
- `discarded`:租户 CRM 未启用或 URL 缺失,任务不会继续重试。
每次尝试都会写入 `crm_webhook_log`,日志只记录 provider、目标 host、请求体和响应摘要不写入 webhook secret。
## 安全边界
- 前端不能直接写 `crm_webhook_queue`
- 前端不能持有 CRM webhook secret。
- 生产环境 webhook 必须使用 HTTPS。
- `WORKER_CRM_ALLOW_INSECURE_LOCALHOST=true` 只用于本地 fake webhook 测试。
- worker 使用数据库服务端连接读取 `app_private.tenant_secrets`,不要把 secret 复制到公共表。
## 后续增强
- 轮询/定向分配销售。
- 钉钉/飞书/企微富卡片模板。
- 失败告警和死信运营后台。
- 批量 CRM 推送、跟进效果统计。