Files
gochat/docs/runbooks/shangwutong-connector.md
T

8.1 KiB
Raw Blame History

商务通 Connector 生产运行手册

架构说明

Shangwutong 是刻意采用的外部 Connector 产品形态,不是内嵌在 GoChat 主进程里的标准 ChannelProvider 插件。GoChat 侧负责 Inbox 配置、凭据下发、durable webhook 投递、消息导入与状态回写;channels/shangwutong 进程负责登录商务通、维护会话、轮询/映射真实协议事件、执行出站发送。这样做的原因是商务通协议需要长连接/心跳/本地游标/不确定投递消歧,独立进程可以隔离故障域、持久化协议状态,并避免把站点密码与会话状态塞进主 API 进程。

因此,Shangwutong 不需要实现 internal/channel.ChannelProvider 的 14 方法接口,也不注册 /webhooks/shangwutong/* 平台回调路由。其稳定契约是:

  • GoChat → Connector/webhooks/gochat/v1,使用 X-Chatwoot-Timestamp + X-Chatwoot-Signature HMAC 签名。
  • Connector → GoChat/api/v1/connector/shangwutong/* 配置/状态 API,以及允许列表中的 account-scoped message/conversation API。
  • GoChat Inbox 类型仍序列化为 Channel::Shangwutong,前端按 API-like inbox 展示和配置。

1. 上线前检查

  1. GoChat 已部署 Channel::Shangwutong migration、Connector service principal、配置/状态 API 和 durable webhook worker。
  2. 为 Connector 创建 account-scoped service token,只 grant 要接入的 Account,不使用人工坐席 JWT。
  3. Connector 与 GoChat 位于受控内部网络;链路跨越不受信网络时由部署层启用 HTTPS、mTLS 或等价隧道。
  4. /data 和备份目录只允许 Connector 运行用户及备份任务访问。Connector 将数据库、WAL/SHM 和在线备份设为 0600,镜像内 /data/backup0700;宿主机挂载目录仍需按相同边界配置。数据库和备份包含明文商务通登录凭据。
  5. 为每个商务通 Inbox 配置相同逻辑 Connector webhook URL;不在 Connector 环境变量中配置账号字段。
  6. 验证主机时钟同步。webhook 签名存在时间窗口,明显时钟漂移会造成全量 401。

2. 首次启动

docker compose up -d postgres redis gochat worker
docker compose run --rm shangwutong migrate up
docker compose up -d shangwutong
docker compose exec shangwutong shangwutong doctor

依次确认:

curl -fsS http://127.0.0.1:9100/healthz
curl -fsS http://127.0.0.1:9100/readyz
curl -fsS http://127.0.0.1:9100/metrics

若端口未发布到宿主机,在容器网络内执行检查。Connector 不以 GoChat health 作为启动前置条件:先恢复 SQLite 中已有 supervisor,首次全量配置快照失败后按 1 秒到 5 分钟指数退避重试;GoChat 恢复后自动完成同步。

3. 灰度顺序

  1. 只创建一个测试 Inbox,确认 lifecycle webhook 返回 202/200Connector 自动创建本地账号。
  2. 在 GoChat 配置页确认 connection_status=connectedcredential_status=applied、actual presence 与 desired presence 一致。
  3. 验证访客文本入站、坐席文本出站、撤回、图片、文件、语音、会话结束和 typing。
  4. 在线切换 online/busy/away/offline;确认只影响目标 Inbox。
  5. 提交错误新密码,确认旧 session 仍工作且配置状态为 rejected;再提交正确密码恢复。
  6. 运行至少一个工作日灰度后分批创建剩余 Inbox,持续观察队列、心跳和认证错误。

4. 日常监控

重点指标:

swt_connector_accounts
swt_connector_supervisors
swt_connector_heartbeat_total
swt_connector_heartbeat_duration_seconds
swt_connector_inbound_queue_depth
swt_connector_outbound_queue_depth
swt_connector_delivery_total
swt_connector_status_sync_total
swt_connector_status_sync_queue_depth
swt_connector_event_mapping_total
swt_connector_unknown_event_total
swt_connector_unmapped_retraction_total
swt_connector_contract_error_total
swt_connector_sqlite_write_duration_seconds

建议告警:connected 比例低于 95%pending 最老记录超过 2 分钟;uncertain 大于 0status sync 超过 2 分钟;未知 kind、raw-only 或 unmapped retraction 持续增长;SQLite 检查失败或卷空间低于 20%。指标标签不包含账号 ID、用户名、session ID 或 Inbox ID。

日志禁止输出 password、pending password、ma、HMAC/webhook secret、Authorization、完整登录 body 和访客正文。发现泄露时先轮换相应 token/secret,再保全并限制日志访问,最后修复 redaction 后重新部署。

5. 备份与恢复

在线备份:

docker compose exec shangwutong shangwutong backup --output /backup/connector-2026-08-01.db

生产与 Quickstart Compose 都将 /backup 挂载为独立持久卷,不与 /data 共用故障域;外部备份系统仍需定期把该卷复制到受控异地存储。

备份完成后在隔离环境执行:

SWT_CONNECTOR_DB_PATH=/restore/connector.db shangwutong migrate status
sqlite3 /restore/connector.db 'PRAGMA integrity_check;'

恢复步骤:停止 Connector;保存当前 DB/WAL/SHM 作为故障证据;将验证通过的备份放回明确的 DB 路径并设为运行用户 0600;启动 Connector;检查 ready、migration、账号数、cursor 和队列深度。恢复不会主动 logout,保存的 session 可优先复用;失效 session 会自动重登。

禁止在运行中用 cp connector.db 作为一致性备份,也不要删除 failed/uncertain 记录来“清空告警”。

6. 升级与回滚

升级前:

docker compose exec shangwutong shangwutong backup --output /backup/pre-upgrade.db
docker compose exec shangwutong shangwutong doctor

滚动步骤:拉取新镜像;执行 migrate up;向旧进程发送 SIGTERM;确认 30 秒内退出;启动新进程;确认 ready、supervisor 数、cursor 和 queue;抽样真实收发。停止期间 GoChat durable webhook 会重试,商务通 session 不执行主动 logout。

崩溃恢复时,遗留 inbound delivering 回到 pending;遗留 outbound delivering 转 uncertain,禁止无证据重发。uncertain 在唯一 kind=3 回显确认或 5 分钟观察超时后解除屏障。

回滚只允许使用能读取当前 schema 的镜像。回滚前暂停 Inbox 配置修改并备份;不要清空 SQLite、cursor 或 GoChat durable jobs。

7. 故障处理

  • auth_failed:核对 Inbox 的 session ID、username、最近密码版本;不要直接改 SQLite。通过 GoChat 配置页提交新密码。
  • verification_required:当前不自动绕过 vcode/ecsq。保留账号离线,按真实商务通客户端完成人工验证并记录流程证据。
  • relogin_required / tickint_resetConnector 会清理 token 并用保存密码重登;观察是否形成登录风暴。
  • inbound 堆积:检查 GoChat Application/Public API、service token grant 和附件下载;cursor 已在原始事件持久化后推进,不要回退 cursor 猜测重放。
  • outbound uncertain:等待观察窗口和 kind=3;不要重复点击发送。超时 failed 后才允许显式 retry。
  • invalid_signature:检查 Inbox webhook secret、系统时钟和 lifecycle secret 轮换顺序。
  • SQLite BUSY/损坏:停止流量,保全 DB/WAL/SHM,运行只读检查并从验证过的在线备份恢复。

8. 生产证据清单

以下结果必须分别记录,不能用单元测试替代:

  • 真实账号登录、session 恢复、online/busy/away/offline、logout 和密码正确/错误更新。
  • 文本、图片、文件、语音双向收发,撤回及连续相同内容的 uncertain 歧义样本。
  • 负 kind 与 65/66/67 cursor 连续抓包;kind=52 不同版本真实 fixture。
  • vcode/ecsq 人工恢复流程。
  • 500+ 账号连续至少 1 小时:无重复 supervisor、SQLite BUSY、goroutine 泄漏、事件丢失,心跳调度不持续跨周期。
  • GoChat 停机恢复事件总数一致;GoChat 升级期间 supervisor 持续心跳。
  • Connector SIGTERM 30 秒内退出,重启后 cursor 连续且未批量 logout。
  • PRAGMA integrity_checkok,日志和响应扫描不含密码、token 或 secret。

任一真实协议项没有证据时,结论应写“功能已实现/自动化已通过,但该项阻塞生产上线”,不得标记为生产验证完成。