## [ERR-20260427-015] CI backend-integration flaky：多 PR 共享 runner + 共享 postgres 容器

**日期**: 2026-04-27
**类别**: CI / 测试基础设施
**严重度**: 中（CI ~25% 通过率，需要重跑碰运气）

### 问题描述
PR #147 上同一段代码在 4 个连续 commit 上：
- commit A（改业务代码）：CI ✅
- commit B、C、D（仅改 .learnings/、.gitea/ 文档）：CI ❌❌❌
- commit E（空 commit `--allow-empty`）：CI ✅

文档 commit 不可能影响测试，但 CI 失败了。重跑就过 → flaky。

### 根因
- `backend-integration` job 跑在 `runs-on: uat-with-docker` self-hosted runner
- runner 上的 `ffoa-test-postgres` 容器**全局共享**（不是每个 CI run 独立起的）
- `force-reset` 用 `DROP DATABASE; CREATE DATABASE` 重建
- 当**两个 PR / 两个 commit 的 CI 并发跑**时：
  - PR_A 跑 force-reset → 它的测试连进 db → 跑 prisma seed
  - PR_B 同时跑 force-reset → DROP 了 PR_A 正在用的 db
  - PR_A 的 seed.ts 中途遇到表不存在 → 抛错 → 测试 setup 失败 → CI 失败
- 哪个 PR 触发顺序在前哪个就赢，~25% 跟另一个不撞撞

### 修复方向（不在当前 PR）
**A. 给 workflow 加并发组**：
```yaml
concurrency:
  group: backend-integration
  cancel-in-progress: false  # 排队，不互相杀
```
所有 backend-integration job 串行，慢但稳。

**B. 给每个 CI run 用独立 db name**：
```sh
TEST_DB_NAME="ffws_integration_test_${GITHUB_RUN_ID}"
```
彻底隔离，并发执行也安全。需要测试结束后清理临时 db。

**C. 用容器隔离**：每个 CI 起独立 postgres 容器（`docker run ffoa-test-postgres-${RUN_ID}`）。最干净，资源开销稍大。

推荐 B 或 C。A 是最简单但慢。

### 启示
- **共享基础设施 + 全局资源命名 = 必踩并发坑**。CI runner 上任何 "global container name + shared state" 都是 flaky 候选
- 排查 flaky test 时，**先看 commit 之间是否真的改了代码**。如果 docs-only commit 也失败，几乎必然是基础设施问题
- 看 CI workflow 的 `runs-on` —— self-hosted vs hosted 表现完全不同。self-hosted 共享一切（disk, network, container names）
- 一个 commit 失败时不要立刻怀疑代码；连续失败但中间一个空 commit 又过，强 flaky 信号

---
