fix(ci): cap postgres fixtures and reclaim leftover compose networks
Independent Staging Quality Gate / validate (push) Successful in 10m28s
Independent Staging Quality Gate / publish (push) Successful in 9m59s

xiaoxin's 20-core npm test opened one Docker network per database file and exhausted default address pools. Limit concurrent fixtures and remove unused jyotisha-postgres networks before the gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-18 19:30:13 +08:00
parent 927bdd7a21
commit 37e62094d7
5 changed files with 171 additions and 2 deletions
+16
View File
@@ -4183,3 +4183,19 @@
- 相关记录:BUG-277(同一段结算逻辑;它删掉的缓冲正是兜底此前不触发的原因之一)、BUG-214(同为契约门与可见输出的耦合)、BUG-271(同一批「失败在回执里查不到」)
- 复发自:无
- 修复版本:待提交
## BUG-281 | staging 质量门 1731/1735xiaoxin 上 Docker 地址池耗尽,4 个 PostgreSQL fixture 起不来
- 状态:resolved(本地修复,待提交与发布)
- 首次发现:2026-08-18
- 最近更新:2026-08-18
- 影响面:Gitea `backend-quality-gate.yml``npm test --prefix frontend``frontend/tests/helpers/postgres-fixture.ts``deploy/reclaim-runner-disk.sh`、xiaoxin runner 上的 Docker user-defined networks
- 用户现象:`927bdd7a` 的 validate 在 1735 项前端测试里红 4 项,日志末尾是两条已通过的 truth-source 合同。失败原文都是 `docker compose up -d --wait postgres` 创建 `jyotisha-postgres-*-app` 网络时返回 `all predefined address pools have been fully subnetted`
- 触发条件:向 `staging` 推送后,xiaoxin20 核)上 `tsx --test``os.availableParallelism()` 并行跑全部 `frontend/tests/*.test.ts`。约 20 个文件会各自 `startPostgresFixture()`,每个 Compose 项目占用一个 user-defined network。
- 根因:两层。其一,质量门跑的是全量并行 `npm test`,而 `test:db` 才把数据库套件串行化;20 核 runner 上一轮实测创建了 26 个 `jyotisha-postgres-*` 网络,其中 4 个在分配子网时失败。其二,BUG-266 的回收脚本只做 `docker network prune --filter until=6h`,同一天内崩溃或未拆掉的 fixture 网络继续占着 Docker default address pools;该 prune 本来就不会删仍有 endpoint 的网络,6 小时门槛对地址池没有额外保护,只会把当天残留留到下次 `compose up` 爆掉。失败的 4 项分别在 `database-local-business``identity-auth-integration``model-configuration-security``rectification-pr4-database`,与 `927bdd7a` 的咨询副运改动无关。
- 修复:fixture 在 `docker compose up` 前领取最多 2 个并发槽(可用 `JYOTISHA_POSTGRES_MAX_FIXTURES` 覆盖),持有期覆盖整个 Compose 项目寿命;槽位用目录锁,进程已死则回收,启动失败与 `stop()` 都会释放。回收脚本在既有 6 小时 prune 之后,对名字匹配 `jyotisha-postgres-` 的网络逐个 `docker network rm`:空闲的删掉,仍有 endpoint 的留下并发 job。
- 验证:`postgres-fixture-contract.test.ts` 2/2、`staging-backend-workflows.test.ts` 38/38 通过(含回收脚本会 `network rm` 残留 `jyotisha-postgres-` 网络、仍拒绝 `docker rm --force` / `system prune`,以及部署脚本 shell 语法)。未做的验证:没有在 xiaoxin 上复跑完整质量门。
- 防复发:Docker user-defined network 和磁盘是两类资源。磁盘回收不能代替地址池回收;`until=6h` 对「今天刚留下的空网络」无效。每个并行测试文件一个 Compose 项目,在多核 runner 上会按核数打满 default address pools。数据库 fixture 必须自己限制并发,不能依赖 `tsx` 默认并行度。
- 相关记录:BUG-266(同一 runner 上的磁盘耗尽与 6 小时网络 prune)、BUG-264(本地全量 `npm test` 并发跑 `database-*` fixture 的既有抖动)
- 复发自:BUG-266(回收只覆盖磁盘与 6 小时以上空网络,未覆盖地址池)
- 修复版本:待提交