8.1 KiB
商务通 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-SignatureHMAC 签名。 - Connector → GoChat:
/api/v1/connector/shangwutong/*配置/状态 API,以及允许列表中的 account-scoped message/conversation API。 - GoChat Inbox 类型仍序列化为
Channel::Shangwutong,前端按 API-like inbox 展示和配置。
1. 上线前检查
- GoChat 已部署
Channel::Shangwutongmigration、Connector service principal、配置/状态 API 和 durable webhook worker。 - 为 Connector 创建 account-scoped service token,只 grant 要接入的 Account,不使用人工坐席 JWT。
- Connector 与 GoChat 位于受控内部网络;链路跨越不受信网络时由部署层启用 HTTPS、mTLS 或等价隧道。
/data和备份目录只允许 Connector 运行用户及备份任务访问。Connector 将数据库、WAL/SHM 和在线备份设为0600,镜像内/data和/backup为0700;宿主机挂载目录仍需按相同边界配置。数据库和备份包含明文商务通登录凭据。- 为每个商务通 Inbox 配置相同逻辑 Connector webhook URL;不在 Connector 环境变量中配置账号字段。
- 验证主机时钟同步。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. 灰度顺序
- 只创建一个测试 Inbox,确认 lifecycle webhook 返回 202/200,Connector 自动创建本地账号。
- 在 GoChat 配置页确认
connection_status=connected、credential_status=applied、actual presence 与 desired presence 一致。 - 验证访客文本入站、坐席文本出站、撤回、图片、文件、语音、会话结束和 typing。
- 在线切换 online/busy/away/offline;确认只影响目标 Inbox。
- 提交错误新密码,确认旧 session 仍工作且配置状态为 rejected;再提交正确密码恢复。
- 运行至少一个工作日灰度后分批创建剩余 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 大于 0;status 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_reset:Connector 会清理 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_check为ok,日志和响应扫描不含密码、token 或 secret。
任一真实协议项没有证据时,结论应写“功能已实现/自动化已通过,但该项阻塞生产上线”,不得标记为生产验证完成。