Files
QMDSearch/.trae/specs/add-async-ingest-tasks/spec.md
T
kplam 51dc8dc4f6 Initial commit: QMDSearch 分层信息检索服务
- FastAPI + Qdrant + Redis + Ollama 技术栈
- L1→L2→L3→chunk 四层分层检索(dense + sparse RRF 融合)
- 文档三级总结与 2.5 级回退
- query 解析路由与分类
- /admin 管理页面
2026-07-29 21:24:40 +08:00

5.1 KiB
Raw Blame History

入库异步任务化 Spec

Why

当前 POST /api/v1/documents 同步等待整条入库流水线(总结→分类→切分→向量化→写库),真实 Ollama 冒烟单篇耗时 39s+,长文档分钟级,客户端/网关易超时,批量导入不可用。改为后台任务模式:提交即返回 task_id,状态可查,失败任务长期保留便于归因。

What Changes

  • BREAKINGPOST /api/v1/documents 由同步返回 IngestionResult200)改为立即返回 {task_id, status}(HTTP 202),流水线在后台 asyncio 任务中执行
  • 新增 GET /api/v1/documents/tasks/{task_id}:查询任务状态(pending/各阶段/done/failed)、完成后的 IngestionResult、失败时的 stage 与错误信息
  • 新增 app/core/ingest_tasks.py IngestTaskManager:提交登记 → 信号量限流并发 → 后台执行 → 状态机推进 → 结果/错误落储
  • 状态存储Redis 为主(key ingest_task:{task_id}JSON);done TTL 24hfailed TTL 7 天(便于失败归因);Redis 不可用时降级进程内字典(重启丢失,日志告警),服务不因此拒绝入库
  • 管理页:入库区块改为「提交 → 轮询任务状态 → 展示进度/结果/失败详情」
  • 配置新增ingest_max_concurrency(默认 2)、ingest_task_ttl_done(默认 86400s)、ingest_task_ttl_failed(默认 604800s7 天)
  • CLAUDE.md API 清单同步更新(标注 POST /documents 行为变更)

Impact

  • Affected specs: 文档入库 API、管理页面、任务状态存储
  • Affected code:

ADDED Requirements

Requirement: 异步入库提交

系统 SHALL 将 POST /api/v1/documents 改为异步任务模式:校验通过后立即返回 HTTP 202 与 {task_id, status: "pending"},入库流水线在后台任务执行;并发后台任务数受 ingest_max_concurrency 信号量限制,超限任务保持 pending 排队。请求体与校验规则(text 非空等)与现状一致,校验失败仍同步返回 1001。

Scenario: 提交即返回

  • WHEN 提交合法文档
  • THEN 响应 202 + task_id,无需等待流水线完成;后台任务按并发额度开始执行

Requirement: 任务状态查询

系统 SHALL 提供 GET /api/v1/documents/tasks/{task_id}:返回 {task_id, status, created_at, updated_at}status 取值 pending | summarizing | classifying | embedding | writing | done | failed(与流水线阶段一致推进);done 时附 result(完整 IngestionResultdocument_id/category/tags/总结层级/chunks_count);failed 时附 error: {stage, message}stage 来自 IngestionError,已产出总结不丢失一并附在 error.partial_summary)。task_id 不存在返回 code=1004。

Scenario: 生命周期

  • WHEN 提交后轮询 task_id
  • THEN 依次观察到 pending→阶段状态→done(result 可查,文档已可检索);失败任务观察到 failed + error.stage

Requirement: 状态存储与保留

任务状态 SHALL 写入 Redisingest_task:{task_id}JSON):done TTL=ingest_task_ttl_done(默认 24h),failed TTL=ingest_task_ttl_failed(默认 7 天),进行中状态 TTL 取 done 值。Redis 不可用时降级进程内字典并日志告警,入库与查询照常(重启后历史任务丢失可接受,接口语义不变)。

Scenario: Redis 宕机降级

  • WHEN Redis 连接失败
  • THEN 提交与查询仍正常,仅日志 warning;进程重启后任务状态丢失

Requirement: 管理页入库区块

管理页入库表单 SHALL 改为:提交后展示 task_id 与状态进度条/文本,每 2s 轮询任务接口,done 展示分类/标签/总结层级/chunks_countfailed 展示 error.stage 与 message;轮询期间禁止重复提交,超时(5 分钟)停止轮询并提示可稍后手动查询。

Requirement: 并发控制

后台入库 SHALL 用 asyncio 信号量限制并发(默认 2),避免多任务同时打满 Ollama/embedding;排队任务状态保持 pending。

MODIFIED Requirements

Requirement: POST /api/v1/documents(行为变更)

原同步返回 IngestionResult 的行为废弃,改为 202 + task_id。所有既有调用方(管理页、既有测试)同步适配;响应体统一响应包装不变({code:0, data:{task_id,status}, message:"ok"}HTTP 状态码 202)。

REMOVED Requirements

Requirement: 同步入库等待

Reason:长耗时流水线导致客户端超时、无法批量导入。 Migration:调用方改为提交后轮询 GET /api/v1/documents/tasks/{task_id};管理页已内置轮询。