更新
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m35s

This commit is contained in:
2026-08-13 12:31:47 +08:00
parent fcfa347005
commit e134552ec5
13 changed files with 458 additions and 188 deletions

View File

@@ -0,0 +1,90 @@
# 生产环境运行说明
## 元数据
- 用途:区分生产与测试运行方式,并为人工发布、迁移和回滚提供事实入口。
- 适用范围:`xm-iot.cn` 的生产 API 与 Worker不适用于本地、测试环境或 Docker Compose。
- 事实源:生产维护者提供的主机与目录信息;实际 systemd Unit、线上 `.env.prod``migrate version` 输出优先于本文。
- Owner生产维护者。
- 最后核验2026-08-13基于维护者提供的信息未连接生产环境
- 更新触发Unit、目录、进程数、Worker 角色、发布顺序、迁移方式或回滚方式变化。
- 验证由维护者在服务器执行本文列出的只读核对命令并回填结果Agent 不连接生产环境。
## 与测试环境的边界
生产环境不是仓库中的 Docker Compose 测试部署:
| 项目 | 生产环境 | 仓库 Compose/工作流 |
| --- | --- | --- |
| 平台 | Ubuntu 24.04 x86_64 | 测试环境自动部署 |
| 发布 | 本地交叉编译后手工上传二进制 | Gitea 构建、镜像与 Docker Compose |
| 进程管理 | systemd | Docker Compose |
| 运行单元 | 1 个 API、1 个调度 Worker、3 个执行 Worker | 不作为生产拓扑依据 |
| 配置 | 每个运行目录的 `.env.prod` | Compose `environment` |
| 回滚 | 覆盖为部署前备份的二进制,必要时恢复数据库备份 | 不适用 |
不得从 `.gitea/workflows/deploy.yaml``docker-compose.prod.yml` 或其中的测试配置推断生产地址、凭据、发布步骤或运行拓扑。
## 已确认运行布局
- 主机Ubuntu 24.04.4 LTS`x86_64`
- API 服务 `junhong-cmp-api.service`:工作目录与程序分别为 `/opt/junhong_cmp/api``/opt/junhong_cmp/api/api`,通过同目录 `.env.prod` 加载环境变量;旧二进制备份在 `releases/`
- 调度 Worker 服务 `junhong-cmp-worker.service`:工作目录与程序分别为 `/opt/junhong_cmp/worker``/opt/junhong_cmp/worker/worker`,通过根目录 `.env.prod` 加载环境变量。
- 三个执行 Worker 服务 `junhong-cmp-worker-1.service``junhong-cmp-worker-2.service``junhong-cmp-worker-3.service`:共享 `/opt/junhong_cmp/worker/worker` 这一份二进制;工作目录和 `EnvironmentFile` 分别是 `worker-1/``worker-2/``worker-3/` 下的 `.env.prod`。因此发布只替换根目录的 `worker`,不复制三份二进制。
- 五个 Unit 都以 `root``Restart=always``RestartSec=3` 运行,标准输出和错误写入 journald。
- Worker 拓扑:调度实例已确认 `JUNHONG_WORKER_ROLE=leader``JUNHONG_WORKER_INSTANCE_NAME=leader`;三个执行实例均为 `JUNHONG_WORKER_ROLE=consumer`。当前三个执行实例的 `JUNHONG_WORKER_INSTANCE_NAME` 都是 `worker-1`,会混淆日志与 Outbox Relay 实例标识;七月发布前须分别修正为 `worker-1``worker-2``worker-3`
- 域名:`xm-iot.cn`API 域名:`cmp-api.xm-iot.cn`
- 企微回调由自建企微中台 `wecom.xm-iot.cn` 配置;支付和运营商回调由各官方平台配置。
## 构建与上传
维护者当前在本地构建:
```bash
GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o ./build/api ./cmd/api
GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o ./build/worker ./cmd/worker
```
本次迭代更新只上传 API 与 Worker 二进制;配置变化由维护者直接修改各运行目录的 `.env.prod`。生产迁移文件必须随本次发布上传到 API 目录下的 `migrations/`,供 `migrate` 记录和执行。生产服务器当前尚未安装 `migrate`;安装路径和版本待首次迁移前确认。
## 配置规则
- 二进制只从嵌入默认配置和 `JUNHONG_` 环境变量读取;`.env.prod` 必须由 systemd Unit 显式加载,或由 Unit 启动脚本 `source` 后启动。需要以 Unit 内容核实实际方式。
- API 与 Worker 共享数据库、Redis、日志、JWT、对象存储、Gateway、短信、支付等基础配置只记录键名不将实际凭据写入仓库文档。
- 七月新增的 API/Worker 共用配置:`JUNHONG_APPROVAL_LEGACY_REFUND_MANUAL_ENABLED``JUNHONG_APPROVAL_LEGACY_OFFLINE_RECHARGE_PAY_ENABLED``JUNHONG_WECOM_BASE_URL``JUNHONG_WECOM_TIMEOUT`
- 七月新增的 Worker 配置:`JUNHONG_WORKER_ROLE``JUNHONG_WORKER_INSTANCE_NAME``JUNHONG_WORKER_AUDIT_RETENTION_CLEANUP_ENABLED`
- 首发要求:退款人工入口、线下充值人工确认、企微审批、运营商实名回调、微信/支付宝在线充值均按维护者决定启用;审计物理清理保持关闭。
- 企微应用凭据由后台配置写入数据库明文字段;这不是启动环境变量。本文不记录其值。
## 人工发布与迁移
已确认顺序:备份二进制和数据库 → 上传二进制及迁移文件 → 停止 systemd 服务 → 执行迁移 → 启动服务。
生产当前迁移版本已于 2026-08-13 由维护者在 API 目录验证为 `140`(非 dirty。历史迁移已归档生产从 `140` 向后执行根目录 `migrations/``141+` 迁移;七月分支最终目标为 `206`。根目录不存在 `173` 号迁移,这是正常编号空档。执行前先以显式 `DB_*` 参数运行:
```bash
DB_HOST=<生产主机> DB_PORT=<端口> DB_USER=<用户> \
DB_PASSWORD='<密码>' DB_NAME=<库名> DB_SSLMODE=<模式> \
./scripts/migrate.sh version
DB_HOST=<生产主机> DB_PORT=<端口> DB_USER=<用户> \
DB_PASSWORD='<密码>' DB_NAME=<库名> DB_SSLMODE=<模式> \
./scripts/migrate.sh up
```
迁移失败时不启动新二进制;按失败迁移的事务状态决定处理,必要时恢复已确认可用的数据库备份。启动失败时覆盖回部署前备份的二进制,再恢复数据库备份(如迁移已改变数据库)。
### 锁的含义与发布影响
`000171` 会对 `tb_agent_wallet``000178` 会对 `tb_iot_card` 使用 PostgreSQL `ACCESS EXCLUSIVE` 锁。该锁执行期间会阻塞该表的读写及其他 DDL直到迁移事务提交或回滚若有未结束业务查询/事务,它也会等待。因此必须在 API 和全部 Worker 停止后执行,并在迁移前检查没有长事务。锁持续时间取决于表数据量、索引创建和等待中的旧事务;不能从仓库估算具体秒数。
## 待维护者确认的最小信息
1. `migrate` 的安装路径、版本和迁移文件上传命令;确认 `140` 到首个根目录迁移版本之间是否存在待补的迁移文件。
2. 数据库恢复的准确命令、恢复前提,以及发布前新建备份的执行人。
3. 已停止服务后的锁前检查命令/结果(至少确认无长事务),以及可接受维护窗口。
4. 企微中台转发到 API 的最终回调路径;支付与运营商平台配置的回调 URL 清单(可脱敏域名外路径)。
## 已确认数据库备份
每日凌晨 02:00 自动备份 `junhong_cmp_prod`:数据库运行在 Docker 容器 `postgres` 中,备份脚本执行 `pg_dump -Fc -Z 6`,写入 `/data/backups/postgresql/<库名>_<时间>.dump`,同时生成 MD5 文件并以 `pg_restore --list` 校验结构;保留 30 天。发布前仍须人工新建一次备份并确认校验通过,不能只依赖凌晨的最近备份。恢复命令待维护者实际演练或确认后补充。

View File

@@ -93,6 +93,19 @@
- **最后验证日期**2026-08-07
- **更新触发条件**:数据访问基础设施变化
## ENG-DB-002
- **状态**:生效
- **适用范围**Agent 对项目数据库的诊断、核对与只读查询。
- **规则**MUST 使用 dbhub MCP测试/本地库使用 `mcp__dbhub__execute_sql_main`,正式库使用 `mcp__dbhub__execute_sql_pro_main`MUST NOT 通过 `psql`、连接串、环境变量或其他命令行客户端直连数据库。
- **理由**dbhub 提供受控只读访问,避免命令历史、环境凭证和目标库选择漂移。
- **最小正例**:调用 `mcp__dbhub__execute_sql_main` 查询订单与佣金记录。
- **最小反例**`source .env && psql ...`
- **机械检查/人工原因**:审查 Agent 执行记录中的数据库访问工具;仓库业务 Go 代码不受本条约束,仍遵守 ENG-DB-001。
- **例外条件**维护者明确提供的、需执行写入或迁移的人工操作按生产运行说明执行Agent 不代执行。
- **Owner**:基础设施负责人
- **最后验证日期**2026-08-13
- **更新触发条件**dbhub MCP 名称、访问范围或数据库运维边界变化
## ENG-MIG-001
- **状态**:生效
- **适用范围**`migrations/` 当前根目录

View File

@@ -0,0 +1,18 @@
# reliable-order-commission-dispatch 验证记录
2026-08-13
```text
GOCACHE=/private/tmp/junhong-go-cache go build ./cmd/api ./cmd/worker
exit=0
openspec validate --all
Totals: 17 passed, 0 failed (17 items)
gofmt -d internal/infrastructure/commissiondelivery/event.go internal/service/order/service.go internal/service/refund/approval_decision.go internal/service/refund/service.go internal/task/auto_purchase.go cmd/worker/main.go
exit=0无输出
```
静态可复现核验:`rg` 确认所有已支付订单路径在事务内调用 `AppendCommissionCalculate`,退款审批路径写入两个稳定 Outbox 事件;`go func` 与直接 `commission:calculate` 入队均不再位于订单、退款和自动购包路径。补偿扫描按状态分页,缺失事件创建、失败事件复位为待投递,并记录已补发、无需补发和失败计数。
`./scripts/context-health.sh` 当前返回非零:仓库既有 `.scratch/` 目录仍在,输出为“禁止目录或文件仍存在:.scratch”。