Files
foka-ci/docs/architecture/design-0004-execution-queue.md
hurole d22fdc9618 feat: 实现环境变量预设功能 & 移除稀疏检出
## 后端改动
- 添加 Project.envPresets 字段(JSON 格式)
- 移除 Deployment.env 字段,统一使用 envVars
- 更新部署 DTO,支持 envVars (Record<string, string>)
- pipeline-runner 支持解析并注入 envVars 到环境
- 移除稀疏检出模板和相关环境变量
- 优化代码格式(Biome lint & format)

## 前端改动
- 新增 EnvPresetsEditor 组件(支持单选/多选/输入框类型)
- 项目创建/编辑界面集成环境预设编辑器
- 部署界面基于预设动态生成环境变量表单
- 移除稀疏检出表单项
- 项目详情页添加环境变量预设配置 tab
- 优化部署界面布局(基本参数 & 环境变量分区)

## 文档
- 添加完整文档目录结构(docs/)
- 创建设计文档 design-0005(部署流程重构)
- 添加 API 文档、架构设计文档等

## 数据库
- 执行 prisma db push 同步 schema 变更
2026-01-03 22:59:20 +08:00

167 lines
6.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.
---
title: 设计文档 0001 - 部署执行队列与重试(基于当前实现)
summary: 记录当前 ExecutionQueue 的行为与下一步改进方向,便于团队对齐。
owners:
- team: backend
reviewers:
- ops-team
status: draft
date: 2026-01-03
version: 0.1.0
related:
- code: apps/server/libs/execution-queue.ts
- code: apps/server/controllers/deployment/index.ts
- schema: apps/server/prisma/schema.prisma
---
# 设计文档 0001部署执行队列与重试
## 1. 背景Context
当前服务端在启动时会初始化执行队列(`ExecutionQueue.initialize()`),用于从数据库恢复 `status=pending` 的部署任务并按顺序执行流水线。
现有相关事实(来自当前代码):
- 服务启动入口:`apps/server/app.ts`
- 路由:`/api/deployments`(创建部署后入队)与 `/api/deployments/:id/retry`(复制记录后入队)
- 数据库SQLite + PrismaDeployment 存在 `status` 字段注释标明pending/running/success/failed/cancelled
- 队列实现:内存队列 `pendingQueue` + `runningDeployments` Set并有轮询机制默认 30 秒)把 DB 中的 pending 任务补进队列
## 2. 目标Goals
- [ ] 明确“部署任务”从创建到执行的状态流转与约束
- [ ] 明确重试语义retry 会创建新 deployment而不是复用原记录
- [ ] 降低重复入队/重复执行的风险(幂等与并发边界清晰)
- [ ] 让运维/排障更容易:关键日志点与可观测性清单
## 3. 非目标Non-goals
- 不引入外部消息队列(如 Redis/Kafka仍以当前内存队列 + DB 恢复为基础
- 不在本文直接实现大规模调度/分布式 runner后续 ADR/设计再做)
## 4. 需求与范围Requirements & Scope
### 功能需求
- 创建部署:写入一条 Deployment 记录,初始状态为 `pending`,并加入执行队列
- 重试部署:通过 `/deployments/:id/retry` 创建一条新的 Deployment 记录(复制必要字段),并加入执行队列
- 服务重启恢复:服务启动后能从 DB 找回仍为 `pending` 的任务并继续执行
### 非功能需求
- 可靠性服务重启不会“丢任务”pending 的任务能恢复)
- 幂等性:避免同一个 deployment 被重复执行
- 可观测性:能定位某次部署为何失败、何时开始/结束、队列长度
## 5. 方案概览High-level Design
当前方案核心链路如下:
1) API 创建 Deploymentstatus=pending
2) `ExecutionQueue.addTask(deploymentId, pipelineId)` 入队
3) `ExecutionQueue.processQueue()` 串行消费 `pendingQueue`
4) `executePipeline()` 会读取 Deployment 与关联 Project获取 `projectDir`,然后创建 `PipelineRunner` 执行
5) 定时轮询:每 30 秒扫描 DB 中的 pending 任务,若不在 `runningDeployments` 集合则补入队列
## 6. 详细设计Detailed Design
### 6.1 接口/API 设计
#### 创建部署
- POST `/api/deployments`
- 行为:创建 Deployment 后立即入队
#### 重试部署
- POST `/api/deployments/:id/retry`
- 行为:读取原 deployment -> 创建新 deploymentstatus=pending-> 入队
- 语义:重试是“创建一个新的任务实例”,便于保留历史执行记录
### 6.2 数据模型/数据库
Deployment 当前关键字段(见 schema 注释):
- `status`: pending/running/success/failed/cancelled目前入队依赖 pending
- `buildLog`: 执行日志(当前创建时写空字符串)
- `startedAt`/`finishedAt`: 时间标记(目前 created 时 startedAt 默认 now
建议补齐/明确(文档层面约束,代码后续落地):
- 状态迁移:
- `pending` -> `running`(开始执行前)
- `running` -> `success|failed|cancelled`(结束后)
- 幂等控制:
- 以 deploymentId 为“单次执行唯一标识”,同一个 deploymentId 不允许重复开始执行
### 6.3 队列/轮询/并发
现状:
- `runningDeployments` 同时承担“已入队/执行中”的去重集合
- `pendingQueue` 为内存 FIFO
- 单实例串行消费(`processQueue` while 循环)
- 轮询间隔常量 30 秒
风险点(需要在文档中明确约束/后续逐步修正):
- 多实例部署:如果将来启动多个 server 实例,每个实例都可能轮询到同一条 pending 记录并执行(需要 DB 锁/租约/状态原子更新)
- 状态更新缺口:当前 `ExecutionQueue` 代码中没有看到明确把 status 从 pending 改成 running/failed/success 的逻辑(可能在 `PipelineRunner` 内处理;若没有,需要补齐)
建议(不改变整体架构前提):
- 将轮询间隔改为可配置 env`EXECUTION_POLL_INTERVAL_MS`(默认 30000
- 在真正执行前做一次 DB 原子“抢占”:仅当 status=pending 时更新为 running并记录开始时间更新失败则放弃执行
### 6.4 可观测性
最低要求(建议后续落地到代码/日志规范):
- 日志字段deploymentId、pipelineId、projectId、projectDir、status
- 队列指标pendingQueue length、runningDeployments size
- 失败记录:捕获异常 message/stack避免泄露敏感信息
### 6.5 安全与权限
当前接口层面需要确认:
- `/api/deployments``/api/deployments/:id/retry` 是否需要登录/鉴权(取决于 middleware 配置)
- 若需要鉴权:建议限制为有项目权限的用户才能创建/重试部署
## 7. 影响与权衡Trade-offs
- 继续采用内存队列:实现简单,但天然不支持多实例并发安全
- DB 轮询恢复:可靠性提升,但会带来额外 DB 查询压力
## 8. 兼容性与迁移Compatibility & Migration
- 文档层面不破坏现有 API
- 若引入 status 原子抢占,需要确保旧数据/旧状态兼容(例如对历史 pending 记录仍可恢复)
## 9. 测试计划Test Plan
- 集成链路:创建 deployment -> 入队 -> 触发执行(可用假 runner
- 重启恢复:插入 pending 记录 -> initialize() -> 任务被 addTask
- 重试接口:原记录存在/不存在的分支
## 10. 发布计划Rollout Plan
- 先补齐文档 + 最小日志规范
- 再逐步落地status 原子抢占 + 轮询间隔 env
## 11. 备选方案Alternatives Considered
- 引入 Redis 队列BullMQ 等):更可靠、支持多实例,但复杂度上升
- 使用 DB 作为队列(表 + 锁/租约):更可靠,但需要严格的并发控制
## 12. 风险与开放问题Risks & Open Questions
- Q1`PipelineRunner` 是否负责更新 Deployment.status如果没有状态机应由谁维护
- Q2服务是否计划多实例部署如果是必须补齐“抢占执行”机制
## 13. 附录Appendix
- 代码:`apps/server/libs/execution-queue.ts`
- 控制器:`apps/server/controllers/deployment/index.ts`
- Schema`apps/server/prisma/schema.prisma`