feat(channels): add Shangwutong connector

This commit is contained in:
2026-08-03 10:13:40 +08:00
parent 96f5c796a6
commit 897b4e018f
126 changed files with 20207 additions and 272 deletions
File diff suppressed because it is too large Load Diff
+124
View File
@@ -0,0 +1,124 @@
# 商务通 Connector 生产运行手册
## 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``/backup``0700`;宿主机挂载目录仍需按相同边界配置。数据库和备份包含明文商务通登录凭据。
5. 为每个商务通 Inbox 配置相同逻辑 Connector webhook URL;不在 Connector 环境变量中配置账号字段。
6. 验证主机时钟同步。webhook 签名存在时间窗口,明显时钟漂移会造成全量 401。
## 2. 首次启动
```bash
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
```
依次确认:
```bash
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=connected``credential_status=applied`、actual presence 与 desired presence 一致。
3. 验证访客文本入站、坐席文本出站、撤回、图片、文件、语音、会话结束和 typing。
4. 在线切换 online/busy/away/offline;确认只影响目标 Inbox。
5. 提交错误新密码,确认旧 session 仍工作且配置状态为 rejected;再提交正确密码恢复。
6. 运行至少一个工作日灰度后分批创建剩余 Inbox,持续观察队列、心跳和认证错误。
## 4. 日常监控
重点指标:
```text
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. 备份与恢复
在线备份:
```bash
docker compose exec shangwutong shangwutong backup --output /backup/connector-2026-08-01.db
```
生产与 Quickstart Compose 都将 `/backup` 挂载为独立持久卷,不与 `/data` 共用故障域;外部备份系统仍需定期把该卷复制到受控异地存储。
备份完成后在隔离环境执行:
```bash
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. 升级与回滚
升级前:
```bash
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。
任一真实协议项没有证据时,结论应写“功能已实现/自动化已通过,但该项阻塞生产上线”,不得标记为生产验证完成。