Files
ZY-Agent/docs/multi-tenant-redesign/03-impl/pr1-postgres-setup.md
T
1445043649 85a14f4c05 docs(impl): PR1 implementation note + acceptance checklist
记录 Stage 0 PR1 的实施落点、关键 LOCK 决策、fixture 用法示例、跟进项与
10 commit 列表。验收:3085 passed + 23 skipped + 0 failed(无 regression),
PG smoke 在 docker daemon 起来后实跑(CI workflow 已配)。

Stage 0 PR1 T1.10. PR1 完成。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:58:21 +08:00

100 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PR1 · Postgres 接入 + testcontainers fixture
> 实现笔记。对应 [docs/superpowers/plans/2026-05-10-stage-0-multi-tenant-foundation.md](../../superpowers/plans/2026-05-10-stage-0-multi-tenant-foundation.md) PR1T1.1-T1.10)。
>
> 状态:**已落地**10 commits 提交在 branch `feat/stage-0-pr1-postgres-fixture`。
## 范围
让 DeerFlow 仓储测试 + dev 部署能跑在 Postgres 上,**不切默认 backend**PR2 的事)。即:
- `postgres-test` optional extraharness + backend)→ `testcontainers[postgres] 4.x` + 复用现有 `postgres` extraasyncpg / psycopg / langgraph-checkpoint-postgres
- `tests/fixtures/postgres.py` 提供 session 级 `postgres_container` + 每 test 一个 ephemeral DB 的 `postgres_url`
- 4 个 smoke test (`tests/test_postgres_smoke.py`) 验证 fixture 隔离 + `init_engine_from_config` 在 PG 上自动建表 + `ThreadMetaRepository` round-trip
- `docker/docker-compose-dev.yaml``postgres:16-alpine` service + healthcheck + named volume
- `scripts/doctor.py` 新增 Database sectionsqlite/postgres/memory 三态探测,PG 实连 + version
- `scripts/setup_wizard.py` Step 3 之后 inline 加一问 "Use Postgres?",默认 Y
- `.github/workflows/backend-postgres-tests.yml` 独立 CI workflow 跑 `pytest -m postgres`
## 验收
- [x] `cd backend && uv sync --group dev --extra postgres-test` 装 testcontainers 成功
- [x] `pytest -m postgres -v` 在本地无 Docker 时**全部 SKIP**fixture 自动跳过)
- [x] 全套 `pytest tests/` 3085 passed + 23 skipped + 0 failedvs baseline 3086 passed + 18 skippeddiff = 4 新 PG smoke skip + 1 env 相关 live test 偶发 skip
- [x] `docker compose -f docker/docker-compose-dev.yaml config --services` 列出 5 services 含 postgresYAML 语法 OK
- [x] `make doctor`sqlite 模式)`Database` section 显示 `database backend = sqlite (.deer-flow/data)`
- [x] `wizard.writer.build_minimal_config(..., database_backend='postgres')` 输出 `database: { backend: postgres, postgres_url: $DATABASE_URL }`
- [ ] CI workflow `backend-postgres-tests` 在 PR 提交后跑通——**待 PR 上去后验证**
- [ ] `docker compose up -d postgres` + `pg_isready` live OK——**待 docker daemon 起**
## 关键决策(lock 项)
| 项 | 选择 | 理由 |
|---|---|---|
| Testcontainers 镜像 | `postgres:16-alpine` | 与远程 RDS 同大版本(待 PR 后用 `SELECT version()` 二次确认) |
| Test 隔离 | per-test database (CREATE/DROP DATABASE) | asyncpg 不支持 URL-embedded `search_path`per-DB 一次 ~50ms,让 test 代码不感知 schema |
| Container scope | session-scoped | per-test container 启动 5-10s 太慢;shared container + per-test DB 是最佳折中 |
| Fixture skip 行为 | Docker 不可用时 `pytest.skip` 而非 `error` | dev 环境无 docker 也能跑其余 3000+ 测试 |
| pytest mark 名 | `postgres` | 简短、与 `no_auto_user` 风格一致 |
| Plugin 注册 | `pytest_plugins = ["fixtures.postgres"]` + sys.path insert | 不加 `tests/__init__.py` 避免影响现有 pytest 发现 |
| CI workflow 拆分 | 独立 `backend-postgres-tests.yml` | 不拖慢 fast unit test loopfork 不强制承担 docker 开销 |
| doctor PG 检查实现 | asyncpg `connect()` + `SELECT version()` | 比 psycopg sync 更与生产路径对齐(生产用 asyncpg) |
| setup_wizard 集成 | inline 问答(不新建 wizard/steps/database.py | 最小改动;后续如需更复杂选项再升级为完整 step 模块 |
## Fixture 用法示例
```python
import pytest
pytestmark = [pytest.mark.postgres, pytest.mark.anyio]
@pytest.fixture
def anyio_backend() -> str:
return "asyncio"
async def test_my_postgres_thing(postgres_url: str) -> None:
from deerflow.persistence.engine import close_engine, init_engine
await init_engine("postgres", url=postgres_url)
try:
# ...your test...
...
finally:
await close_engine() # important: release connections before fixture teardown
```
## 跟进项(不在 PR1 范围)
- **PR2**:默认 backend 切 postgresconfig.example.yaml + .env.example + docker-compose `gateway depends_on postgres`
- **PR1 待 follow-up**:本地 docker daemon 起来后跑一次 `pytest -m postgres -v` 实测;如 PG 大版本不是 16,调 `postgres:16-alpine` → 对应版本
- 如果发现 fixture 启动慢导致 CI 时间不可接受,考虑 [pytest-postgresql](https://pypi.org/project/pytest-postgresql/) 替代 testcontainers(轻量但需要 GitHub Actions service container 而非 testcontainers daemon
## 涉及文件
| 类别 | 文件 |
|---|---|
| 依赖 | `backend/packages/harness/pyproject.toml``backend/pyproject.toml``backend/uv.lock` |
| Fixture | `backend/tests/fixtures/__init__.py``backend/tests/fixtures/postgres.py` |
| Test | `backend/tests/test_postgres_smoke.py` |
| Conftest | `backend/tests/conftest.py`pytest_plugins + sys.path |
| Docker | `docker/docker-compose-dev.yaml` |
| 脚本 | `scripts/doctor.py``scripts/setup_wizard.py``scripts/wizard/writer.py` |
| CI | `.github/workflows/backend-postgres-tests.yml` |
## 提交记录
10 commits(每条 1 task):
```
fab85b14 build(deps): add postgres-test optional extra for testcontainers T1.1
ae4ea46b feat(docker): add postgres service to dev compose T1.2
31361e2d test(fixtures): add testcontainers Postgres fixture for Stage 0 T1.3
8f480cd7 test(persistence): postgres smoke tests for init_engine + ThreadMetaRepo T1.4-T1.6
e6f5ba53 feat(doctor): add Database section probing configured backend T1.7
eae01901 feat(wizard): add Postgres backend question to setup wizard T1.8
a33b46b4 ci(postgres): add Postgres workflow running @pytest.mark.postgres tests T1.9
```
T1.10 的 commit 是这份 doc 本身。