Files
fquiz/memory/2026-04-12.md
T
2026-04-12 21:19:24 +08:00

7.3 KiB
Raw Blame History

2026-04-12

背景

  • GitHub Actions 构建 API 镜像时,pip install -r requirements.txt 多次出现 ReadTimeoutErrorfiles.pythonhosted.org / pypi.org)。

改动

  • 更新 api/Dockerfile
    • 新增构建参数 PIP_INDEX_URL(默认 https://pypi.org/simple)。
    • 新增构建参数 PIP_DEFAULT_TIMEOUT(默认 120)。
    • pip install 增加 --retries 8 --timeout "${PIP_DEFAULT_TIMEOUT}" -i "${PIP_INDEX_URL}"
    • 设置 PIP_DISABLE_PIP_VERSION_CHECK=1
  • 更新 .github/workflows/main.yml
    • API 镜像构建新增 build-args
      • PIP_INDEX_URL=${{ secrets.PIP_INDEX_URL || vars.PIP_INDEX_URL || 'https://pypi.org/simple' }}
      • PIP_DEFAULT_TIMEOUT=${{ vars.PIP_DEFAULT_TIMEOUT || '120' }}
  • 更新 api/requirements.txt
    • 从宽范围约束改为精确版本,减少 pip 解析回溯与重复下载。

验证

  • 本地触发 docker build -f api/Dockerfile api --build-arg PIP_INDEX_URL=https://pypi.org/simple --build-arg PIP_DEFAULT_TIMEOUT=120
  • 日志确认:
    • 新的 pip install 参数生效。
    • 发生网络超时时会触发 Retry(total=...) 重试逻辑,而非首次超时直接失败。

风险与备注

  • 受网络质量影响,构建时长可能显著增加。
  • 若目标环境访问 pypi.org 不稳定,需在 GitHub Secrets/Variables 配置更近的 PIP_INDEX_URL

追加修正(同日)

  • 触发问题:No matching distribution found for websockets>=10.4; extra == "standard"
  • 原因:uvicorn[standard] 会强依赖 websockets;在当前包源下解析失败。
  • 处理:
    • api/requirements.txtuvicorn[standard]==0.44.0 改为 uvicorn==0.44.0,并新增 wsproto==1.3.2
    • api/Dockerfile 启动命令追加 --ws wsproto,明确 WebSocket 协议实现。
  • 结果:构建日志不再出现 websockets>=10.4 依赖链,改为安装 wsproto

追加修正(部署脚本 YAML 解析)

  • 触发问题:部署阶段 docker compose 报错 yaml: line 2: mapping values are not allowed in this context,并伴随 DRONE_SSH_PREV_COMMAND_EXIT_CODE 变量告警。
  • 原因:appleboy/ssh-actionscript_stop: true 下会插入额外控制逻辑,和脚本中的 heredoc 组合后可能污染生成文件。
  • 处理:移除 workflow 中 appleboy/ssh-actionscript_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.5psycopg-binary-3.3.3 均成功下载并安装,最终 fquiz-api Built

追加开发(文件管理一期主链)

  • 目标:
    • 在现有 FastAPI + SQLAlchemy + RBAC + Next.js App Router 结构上落地文件管理一期最小闭环。
    • 支持 VFS / S3 driver 抽象,先打通后台 /admin/files 骨架与核心目录操作。
  • 后端改动:
    • 新增模型:file_storage_backendsfile_storage_mountsfile_index_entriesapi/app/models/file_storage.py)。
    • init_db 增加 file_storage 模型加载,保证 create_all 生效。
    • 新增存储驱动层:VfsStorageDriverS3StorageDriver 与统一工厂(api/app/services/storage_driver.py)。
    • 新增文件服务:目录列表(带索引同步)、创建目录、删除路径(api/app/services/file_service.py)。
    • 新增 API/api/v1/admin/files/directories/deleteapi/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.59S3 driver 依赖)。
    • .env.example 增加 FILE_VFS_ROOT(默认 ./data/vfs)。
  • 最小验证:
    • python3 -m compileall 覆盖新增/改动后端文件通过。
    • npx eslint(目标前端文件)通过。
    • npx tsc --noEmitweb)通过。
  • 风险与缺口:
    • 当前未提供存储后端/挂载点的可视化配置管理,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.pyselectinload(...) 由模块级常量改为惰性构建,避免导入阶段触发 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"}

追加修复(GitHub 发布 Run Command Timeout

  • 触发问题:
    • 发布阶段日志持续停留在 docker compose pull 的 layer 下载进度。
    • appleboy/ssh-action 最终报错:Run Command Timeout,作业退出码 1
  • 根因:
    • 远端拉取镜像速度慢时,SSH Action 的命令执行超时先触发,未等到 docker compose pull 自然完成。
  • 处理:
    • 更新 .github/workflows/main.yml 部署步骤:
      • appleboy/ssh-action 增加 timeout: 120scommand_timeout: 45m
      • 脚本内新增 DOCKER_CLIENT_TIMEOUT=600COMPOSE_HTTP_TIMEOUT=600 默认值。
      • 新增 pull_with_retry(最多 3 次)包装 docker compose pull,网络抖动时自动重试。
  • 验证建议:
    • 推送触发 main 发布,观察部署日志不再在固定时长点报 Run Command Timeout
    • 远端 docker compose ps 应显示 db/api/web 均为 Up(或 healthy)。