Files
gongxue-base/docs/refactor/crm-worker.md

4.8 KiB
Raw Blame History

CRM Webhook Worker

更新时间2026-06-30

apps/worker 是后端异步任务进程,当前 CRM 任务支持客资首绑 webhook 推送和租户后台学生批量跟进推送。API 只负责在客资首绑或学生运营动作时写入 crm_webhook_queueworker 负责消费到期任务、签名、发送、失败重试和写入 crm_webhook_log

运行命令

本地单次消费一批任务:

npm --workspace @tiku-saas/worker run crm:once

或使用根脚本测试:

npm run test:worker:crm

生产常驻:

npm --workspace @tiku-saas/worker run start

建议 API 和 worker 作为两个独立进程部署,共用同一个 DATABASE_URL

配置

环境变量:

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

租户后台配置仍走:

PUT /api/crm/config
GET /api/crm/config
GET /api/crm/queue
GET /api/crm/dead-letters
GET /api/crm/queue/logs
POST /api/crm/queue/action
POST /api/tenant-admin/students/crm-push

密钥必须写入 app_private.tenant_secrets,公共表 crm_config.secret_ref 只保留引用,例如:

app_private.tenant_secrets:crm:webhook

Provider

worker 根据队列 payload 的 provider 或 webhook URL 自动判断:

provider URL 特征 行为
generic 默认 POST { event: "lead.created", data: ... }{ event: "student.crm_push", 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 消息

官方参考:

队列状态

crm_webhook_queue.status

pending -> processing -> sent
pending -> processing -> retrying -> processing -> sent
pending -> processing -> retrying -> failed
pending -> discarded

说明:

  • pending / retrying:等待 worker 消费。
  • processingworker 已抢占任务。
  • sent:目标 webhook 返回 2xx。
  • failed:超过最大重试次数。
  • discarded:租户 CRM 未启用或 URL 缺失,任务不会继续重试。

每次尝试都会写入 crm_webhook_log,日志只记录 provider、目标 host、请求体和响应摘要不写入 webhook secret。

死信运营

CRM 失败运营入口已经落地,租户后台只通过后端 API 处理失败任务:

GET  /api/crm/dead-letters?status=failed&limit=20
GET  /api/crm/queue/logs?queueId=<crmQueueId>
POST /api/crm/queue/action

POST /api/crm/queue/action 当前支持:

{ "queueId": "<crmQueueId>", "action": "retry", "reason": "确认 webhook 已恢复" }
{ "queueId": "<crmQueueId>", "action": "ignore", "reason": "租户确认不再推送" }

安全边界:

  • 读取失败池、查看日志和重试/忽略都要求租户内 crm:write 权限。
  • retry 会把 failed/discarded/retrying/pending 任务重置为 pending,清空错误并记录操作者。
  • ignore 只允许处理 failed/discarded 任务,会标记为 discarded 并记录原因。
  • API 会递归脱敏 payload、日志和审计响应中的 secret、token、authorization、password 等敏感字段。
  • 所有动作都会写入 crm_webhook_log 和租户审计日志,前端不能直接改 crm_webhook_queue

安全边界

  • 前端不能直接写 crm_webhook_queue
  • 前端不能持有 CRM webhook secret。
  • 学生批量推送必须走 POST /api/tenant-admin/students/crm-push,后端会校验 crm:writestudents:readstudents:followups:write、学生范围、班级范围和租户成员指派人。
  • 学生推送 payload 只包含 avatarPreset 默认头像口径,不写入、不回显微信/QQ/旧库头像 URL。
  • 生产环境 webhook 必须使用 HTTPS。
  • WORKER_CRM_ALLOW_INSECURE_LOCALHOST=true 只用于本地 fake webhook 测试。
  • worker 使用数据库服务端连接读取 app_private.tenant_secrets,不要把 secret 复制到公共表。

后续增强

  • 钉钉/飞书/企微富卡片模板。
  • 外部失败告警升级。
  • 更细销售转化看板。