From b88b775f84eba8ac019c6d2485cd636085ceb141 Mon Sep 17 00:00:00 2001 From: chengkai3 Date: Sun, 12 Apr 2026 20:56:24 +0800 Subject: [PATCH] fix(deploy): stabilize db image source and record api recovery --- .github/workflows/main.yml | 3 +- MEMORY.md | 18 +++++++++++ memory/2026-04-12.md | 63 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 56d165e..9685ae6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -123,7 +123,7 @@ jobs: cat > docker-compose.prod.yml <<'YAML' services: db: - image: postgres:16-alpine + image: ${POSTGRES_IMAGE:-docker.m.daocloud.io/library/postgres:16-alpine} container_name: fquiz-db environment: POSTGRES_DB: ${POSTGRES_DB:-fquiz} @@ -205,6 +205,7 @@ jobs: POSTGRES_DB=fquiz POSTGRES_USER=fquiz POSTGRES_PASSWORD=fquiz + POSTGRES_IMAGE=docker.m.daocloud.io/library/postgres:16-alpine ENV echo "[warn] .env 不存在,已写入默认模板,请尽快改成生产配置。" fi diff --git a/MEMORY.md b/MEMORY.md index 77284a5..9f224a9 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -21,3 +21,21 @@ - 路由规则类型固定为:`GLOBAL/CAPABILITY/BUSINESS/AGENT`;其中 `GLOBAL` 保留 key 为 `__global__`。 - 模型删除前必须做引用检查(至少检查路由规则引用);`ENABLED` 状态禁止直接删除。 - 密钥默认只保留 hash + masked + fingerprint,不通过 API 返回明文。 + +## 文件管理口径(2026-04-12) + +- 文件管理一期采用三层模型: + - `file_storage_backends`(后端定义:VFS/S3) + - `file_storage_mounts`(挂载点) + - `file_index_entries`(目录索引快照) +- 后台 API 入口统一在 `/api/v1/admin/files` 前缀,权限码为: + - `file.read`:浏览挂载点和目录列表 + - `file.manage`:创建目录、删除路径 +- 存储驱动抽象位于 `api/app/services/storage_driver.py`,VFS/S3 必须通过同一工厂分发,避免业务层直接耦合具体存储 SDK。 +- VFS 默认根目录由 `FILE_VFS_ROOT` 控制(默认 `./data/vfs`)。 + +## 启动与部署稳定性口径(2026-04-12) + +- SQLAlchemy 关联加载选项(`selectinload/joinedload`)避免在模块导入期以全局常量初始化,优先在函数内惰性构建,防止导入顺序导致 mapper 提前配置失败。 +- `app.models` 包初始化需预加载全部模型模块,确保字符串关系(如 `"AuditLog"`)在启动阶段可解析。 +- 部署 compose 中 DB 镜像应通过 `POSTGRES_IMAGE` 可配置,默认使用镜像站(`docker.m.daocloud.io/library/postgres:16-alpine`)以降低 Docker Hub 网络抖动风险。 diff --git a/memory/2026-04-12.md b/memory/2026-04-12.md index 5fc126f..67a85e9 100644 --- a/memory/2026-04-12.md +++ b/memory/2026-04-12.md @@ -44,3 +44,66 @@ - 触发问题:部署阶段 `docker compose` 报错 `yaml: line 2: mapping values are not allowed in this context`,并伴随 `DRONE_SSH_PREV_COMMAND_EXIT_CODE` 变量告警。 - 原因:`appleboy/ssh-action` 在 `script_stop: true` 下会插入额外控制逻辑,和脚本中的 heredoc 组合后可能污染生成文件。 - 处理:移除 workflow 中 `appleboy/ssh-action` 的 `script_stop: true`,保留脚本内 `set -euo pipefail` 作为失败中断机制。 + +## 追加修正(API 构建超时 + 解析冲突) + +- 触发问题: + - `pip` 拉取 `files.pythonhosted.org` 频繁 `ReadTimeoutError`。 + - 在高延迟场景下,解析 `pydantic` 版本链时出现 `ResolutionImpossible`。 +- 处理: + - `api/requirements.txt` 新增显式锁定: + - `pydantic==2.12.5` + - `pydantic-core==2.41.5` + - 将 `psycopg[binary]==3.3.3` 改为显式双包: + - `psycopg==3.3.3` + - `psycopg-binary==3.3.3` +- 验证: + - `docker compose build api --no-cache` 成功。 + - 日志显示 `pydantic-core-2.41.5` 与 `psycopg-binary-3.3.3` 均成功下载并安装,最终 `fquiz-api Built`。 + +## 追加开发(文件管理一期主链) + +- 目标: + - 在现有 FastAPI + SQLAlchemy + RBAC + Next.js App Router 结构上落地文件管理一期最小闭环。 + - 支持 VFS / S3 driver 抽象,先打通后台 `/admin/files` 骨架与核心目录操作。 +- 后端改动: + - 新增模型:`file_storage_backends`、`file_storage_mounts`、`file_index_entries`(`api/app/models/file_storage.py`)。 + - `init_db` 增加 `file_storage` 模型加载,保证 `create_all` 生效。 + - 新增存储驱动层:`VfsStorageDriver`、`S3StorageDriver` 与统一工厂(`api/app/services/storage_driver.py`)。 + - 新增文件服务:目录列表(带索引同步)、创建目录、删除路径(`api/app/services/file_service.py`)。 + - 新增 API:`/api/v1/admin/files`、`/directories`、`/delete`(`api/app/api/v1/admin_files.py`)。 + - 种子数据增加 `file.read`/`file.manage` 权限、`admin.files` 菜单、默认 VFS backend+mount 与 S3 backend 占位配置。 +- 前端改动: + - 新增后台页面:`web/src/app/admin/files/page.tsx`。 + - 提供挂载点切换、面包屑目录浏览、刷新、新建目录、删除。 + - 增补类型定义 `FileListResponse` 等,并在后台首页新增文件管理入口卡片。 +- 依赖与配置: + - `api/requirements.txt` 增加 `boto3==1.40.59`(S3 driver 依赖)。 + - `.env.example` 增加 `FILE_VFS_ROOT`(默认 `./data/vfs`)。 +- 最小验证: + - `python3 -m compileall` 覆盖新增/改动后端文件通过。 + - `npx eslint`(目标前端文件)通过。 + - `npx tsc --noEmit`(web)通过。 +- 风险与缺口: + - 当前未提供存储后端/挂载点的可视化配置管理,S3 仍需手工写入 backend 配置并启用。 + - 仅实现目录浏览+建目录+删除,未包含上传、下载、移动、重命名、分享、回收站等完整网盘能力。 + +## 追加修复(API 容器 unhealthy + Docker Hub 超时) + +- 触发问题: + - `docker compose up` 阶段 `fquiz-api` 持续 unhealthy(容器反复重启)。 + - 部署日志中 `db` 拉取 `registry-1.docker.io` 超时(`Client.Timeout exceeded while awaiting headers`)。 +- 根因: + - `api/app/services/admin_service.py` 在模块导入期构建 `selectinload(...)` 常量,提前触发 SQLAlchemy mapper 配置;当时 `User.audit_logs -> "AuditLog"` 对应模型尚未注册,导致启动即崩溃。 + - 生产部署 compose 固定 `postgres:16-alpine`,对 Docker Hub 可达性强依赖。 +- 处理: + - `api/app/models/__init__.py` 增加模型模块统一导入,保证关系类可解析。 + - `api/app/services/admin_service.py` 将 `selectinload(...)` 由模块级常量改为惰性构建,避免导入阶段触发 mapper 配置。 + - `.github/workflows/main.yml` 部署生成的 `docker-compose.prod.yml` 中 DB 镜像改为可配置: + - `image: ${POSTGRES_IMAGE:-docker.m.daocloud.io/library/postgres:16-alpine}` + - `.env` 模板新增 `POSTGRES_IMAGE` 默认值。 +- 验证: + - 使用镜像源参数重建 API 成功: + - `docker compose build api --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple --build-arg PIP_DEFAULT_TIMEOUT=600 --build-arg PIP_RETRIES=30` + - `docker compose up -d api` 后状态为 `Up ... (healthy)`。 + - `curl http://127.0.0.1:8000/health` 返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`。