mi-assessment/.kiro/specs/redis-report-queue/requirements.md
2026-02-25 10:19:28 +08:00

7.9 KiB
Raw Blame History

Requirements Document

Introduction

将测评报告生成从当前的同步调用模式改为基于 Redis List 的异步队列处理模式。当前 AssessmentService.SubmitAnswersAsync 在提交答案后直接 await _reportGenerationService.GenerateReportAsync(recordId) 同步生成报告,导致用户请求被阻塞、失败后无重试机制、状态永久卡在"生成中"Status=3。本功能引入 Redis 队列LPUSH/BRPOP+ BackgroundService 消费者模式,实现异步生成、失败自动重试、后台管理手动触发重新生成。

Glossary

  • Queue_Producer: 将报告生成任务推入 Redis 队列的组件,负责构造队列消息并执行 LPUSH 操作
  • Queue_Consumer: 运行在 API 进程中的 BackgroundService通过 BRPOP 从 Redis 队列中消费任务并调用报告生成服务
  • Report_Queue: Redis List 数据结构Key 为 report:queue存储待生成报告的任务消息JSON 格式)
  • Dead_Letter_Queue: Redis List 数据结构Key 为 report:queue:dead,存储超过最大重试次数仍失败的任务消息
  • Queue_Message: 队列中的 JSON 消息体,包含 RecordId测评记录ID、RetryCount已重试次数、EnqueueTime入队时间等字段
  • ReportGenerationService: 现有的报告生成服务,位于 MiAssessment.Core/Services/,核心方法 GenerateReportAsync(long recordId)
  • AssessmentService: 现有的测评服务,位于 MiAssessment.Core/Services/SubmitAnswersAsync 方法中触发报告生成
  • Admin_Record_Controller: 后台管理系统的测评记录控制器,位于 MiAssessment.Admin.Business/Controllers/AssessmentRecordController.cs
  • Assessment_Record: 测评记录实体Status 字段含义1=待测评2=测评中3=生成中4=已完成5=生成失败
  • Max_Retry_Count: 最大重试次数常量,值为 3
  • IRedisService: 现有的 Redis 服务接口,位于 MiAssessment.Core/Interfaces/,需扩展 List 操作方法

Requirements

Requirement 1: 异步入队替代同步生成

User Story: As a 小程序用户, I want 提交测评答案后立即得到响应, so that 不需要等待报告生成完成就能继续使用小程序。

Acceptance Criteria

  1. WHEN 用户提交测评答案成功, THE Queue_Producer SHALL 将包含 RecordId、RetryCount=0、EnqueueTime 的 Queue_Message 序列化为 JSON 并通过 LPUSH 推入 Report_Queue
  2. WHEN 用户提交测评答案成功, THE AssessmentService SHALL 在入队完成后立即返回 SubmitAnswersResponseAssessment_Record 状态保持为 3生成中
  3. IF Redis 连接不可用导致入队失败, THEN THE AssessmentService SHALL 记录错误日志并仍然返回成功响应Assessment_Record 状态保持为 3生成中

Requirement 2: 队列消费与报告生成

User Story: As a 系统运维人员, I want 后台服务自动消费队列中的报告生成任务, so that 报告能在后台异步生成而不阻塞用户请求。

Acceptance Criteria

  1. WHEN API 应用程序启动, THE Queue_Consumer SHALL 作为 BackgroundService 自动启动并持续监听 Report_Queue
  2. WHEN Report_Queue 中存在待处理消息, THE Queue_Consumer SHALL 通过 BRPOP 取出消息并调用 ReportGenerationService.GenerateReportAsync 生成报告
  3. WHEN 报告生成成功完成, THE Queue_Consumer SHALL 记录成功日志Assessment_Record 状态由 ReportGenerationService 更新为 4已完成
  4. WHILE Queue_Consumer 正在处理一条消息, THE Queue_Consumer SHALL 在处理完成后再取出下一条消息(串行处理)
  5. IF Queue_Consumer 在 BRPOP 等待过程中发生异常, THEN THE Queue_Consumer SHALL 记录错误日志并在等待 5 秒后重新开始监听

Requirement 3: 失败重试机制

User Story: As a 系统运维人员, I want 报告生成失败后自动重试, so that 临时性错误不会导致报告永久无法生成。

Acceptance Criteria

  1. WHEN 报告生成抛出异常且 Queue_Message 的 RetryCount 小于 Max_Retry_Count, THE Queue_Consumer SHALL 将 RetryCount 加 1 后重新 LPUSH 到 Report_Queue 尾部
  2. WHEN 重新入队前, THE Queue_Consumer SHALL 按照 RetryCount 计算等待时间第1次重试等待 10 秒第2次等待 30 秒第3次等待 60 秒)后再执行 LPUSH
  3. WHEN 报告生成抛出异常且 Queue_Message 的 RetryCount 等于 Max_Retry_Count, THE Queue_Consumer SHALL 将该消息 LPUSH 到 Dead_Letter_Queue 并更新 Assessment_Record 状态为 5生成失败
  4. WHEN 消息进入 Dead_Letter_Queue, THE Queue_Consumer SHALL 记录包含 RecordId、RetryCount、异常信息的错误日志

Requirement 4: Redis List 操作扩展

User Story: As a 开发人员, I want IRedisService 接口支持 List 操作, so that 队列的生产和消费可以通过统一的 Redis 服务接口完成。

Acceptance Criteria

  1. THE IRedisService SHALL 提供 ListLeftPushAsync(string key, string value) 方法,对应 Redis LPUSH 命令
  2. THE IRedisService SHALL 提供 ListRightPopAsync(string key, TimeSpan timeout) 方法,对应 Redis BRPOP 命令,在超时时返回 null
  3. THE IRedisService SHALL 提供 ListLengthAsync(string key) 方法,对应 Redis LLEN 命令
  4. THE RedisService SHALL 实现上述三个方法,在 Redis 连接不可用时 ListLeftPushAsync 静默返回、ListRightPopAsync 返回 null、ListLengthAsync 返回 0

Requirement 5: 后台管理手动触发重新生成

User Story: As a 后台管理员, I want 在后台管理系统中手动触发重新生成报告, so that 卡在"生成中"或"生成失败"状态的测评记录可以重新生成报告。

Acceptance Criteria

  1. WHEN 管理员对状态为 3生成中或 5生成失败的 Assessment_Record 触发重新生成, THE Admin_Record_Controller SHALL 提供 POST /api/admin/assessmentRecord/regenerateReport 接口接收 RecordId
  2. WHEN 重新生成请求合法, THE Admin_Record_Controller 对应的服务 SHALL 将 Assessment_Record 状态重置为 3生成中清除已有的测评结果数据并将新的 Queue_MessageRetryCount=0LPUSH 到 Report_Queue
  3. IF 指定的 Assessment_Record 不存在或已被软删除, THEN THE Admin_Record_Controller 对应的服务 SHALL 返回错误码和"测评记录不存在"提示
  4. IF 指定的 Assessment_Record 状态不是 3 或 5, THEN THE Admin_Record_Controller 对应的服务 SHALL 返回错误码和"当前状态不允许重新生成"提示

Requirement 6: 批量重新生成

User Story: As a 后台管理员, I want 批量触发多条卡住的测评记录重新生成报告, so that 历史遗留的"生成中"状态记录可以一次性处理。

Acceptance Criteria

  1. THE Admin_Record_Controller SHALL 提供 POST /api/admin/assessmentRecord/batchRegenerateReport 接口接收 RecordId 列表
  2. WHEN 批量重新生成请求合法, THE Admin_Record_Controller 对应的服务 SHALL 对每条符合条件(状态为 3 或 5的 Assessment_Record 执行与单条重新生成相同的逻辑
  3. WHEN 批量操作完成, THE Admin_Record_Controller 对应的服务 SHALL 返回成功入队数量和跳过数量(因状态不符或记录不存在而跳过)
  4. IF RecordId 列表为空, THEN THE Admin_Record_Controller 对应的服务 SHALL 返回错误码和"记录ID列表不能为空"提示

Requirement 7: 生成失败状态支持

User Story: As a 开发人员, I want Assessment_Record 支持"生成失败"状态, so that 超过最大重试次数的记录有明确的失败标识。

Acceptance Criteria

  1. THE Assessment_Record SHALL 支持 Status=5 表示"生成失败"状态
  2. WHEN 小程序用户查询状态为 5 的 Assessment_Record, THE AssessmentService SHALL 返回"报告生成失败,请联系客服"的状态描述
  3. WHEN 后台管理员查询测评记录列表, THE Admin_Record_Controller 对应的服务 SHALL 在状态筛选中支持 Status=5生成失败的筛选条件