修复重新上报导致任务状态与 Outbox 不一致 #91

Closed
opened 2026-08-10 11:06:47 +08:00 by ila · 2 comments
Owner

基本信息

  • 类型:缺陷
  • 父级大工单:#1
  • 所属 MVP / 版本:#2
  • 阶段:Client 任务重试与结果可靠上报

要解决什么

已完成采集任务在后续重新采集失败后,会产生待发送的 task_failure。此时如果手工“重新上报”旧的 collect_result,通用的 mark_outbox_sent() 会无条件把任务主状态改回 succeeded,形成以下矛盾:

  • 表格显示“已完成”;
  • 最新执行记录实际失败;
  • 同一任务仍有未发送的失败 Outbox;
  • 点击“重新执行”又被“仍有未发送的结果”拦截。

现场记录 COL-3dec8b1e10f28954 已复现:旧结果已发送,最新 task_failure 为 pending。

做什么 / 不做什么

  • 做:历史结果重新上报只更新 Outbox,不覆盖任务最新执行状态。
  • 做:重新上报时优先处理任务尚未发送的 Outbox,包括 task_failure;没有未发送事件时才重发最新结果。
  • 做:发送失败事件成功后,按该事件对应的最新执行恢复任务失败状态,修复已经产生的“假完成”记录。
  • 做:重新执行拦截提示明确说明未发送的是结果还是失败信息,并给出恢复路径。
  • 做:补充 Repository、事件 Worker 和状态一致性回归测试。
  • 不做:不修改 Admin 接口和数据库表结构。
  • 不做:不操作 Android 设备,不触发采集、采购或真实下单。
  • 不做:不自动删除历史结果或失败记录。

怎么做

  • 在 client/src/task_repository.py 中区分“首次结果提交成功”和“历史事件重新上报成功”的状态更新语义。
  • 新增按任务选择待上报事件的方法:优先返回未发送事件;没有时返回最新结果事件。
  • 失败事件发送成功时,只在它属于最新一次执行时恢复任务的失败状态,避免旧失败覆盖新结果。
  • 在 client/src/pdd_ui_event.py 中让重新上报 Worker 使用新的事件选择和完成方法。
  • 调整重新执行校验文案,并同步 docs/client/03-data-model.md、docs/client/05-ui-specification.md 中的稳定规则。
  • 预计修改测试:client/test/test_task_repository.py、client/test/test_pdd_ui_event.py。

验收标准

  • 重发旧的已发送采集结果不会把最新失败任务改成“已完成”。
  • 存在待发送 task_failure 时,“重新上报”优先发送该失败事件。
  • 最新失败事件上报成功后,任务保持或恢复为该次执行对应的失败状态。
  • 旧失败事件上报成功不会覆盖更新一次执行产生的成功状态。
  • 没有未发送事件时,仍能重发最新采集或采购结果。
  • 重新执行遇到未发送失败事件时显示准确中文提示。
  • 不创建重复 Outbox,不修改 Admin 接口,不调用 Android 自动化。
  • Client 完整自动测试通过。

怎么验证

从 client/ 目录执行:

C:/Python310/python.exe -m unittest discover -s test -p "test_task_repository.py"
C:/Python310/python.exe -m unittest discover -s test -p "test_pdd_ui_event.py"
C:/Python310/python.exe -m unittest discover -s test -p "test_*.py"

使用临时 SQLite 构造“旧结果已发送 → 新执行失败未上报 → 手工重新上报”的时间线,核对任务状态、事件选择和幂等键。真实 Admin 联调单独记录,不操作手机。

风险和回退

  • 风险:错误恢复任务状态可能让旧失败覆盖新结果;必须同时校验事件的 attempt_id 与最新 task_runs。
  • 风险:重新上报语义从“仅结果”扩展为“优先未发送事件”,需要保持原幂等键,避免 Admin 重复落库。
  • 回退:按本工单提交整体回退;数据库无结构迁移,历史 Outbox 数据保持不变。
## 基本信息 - 类型:缺陷 - 父级大工单:#1 - 所属 MVP / 版本:#2 - 阶段:Client 任务重试与结果可靠上报 ## 要解决什么 已完成采集任务在后续重新采集失败后,会产生待发送的 `task_failure`。此时如果手工“重新上报”旧的 `collect_result`,通用的 `mark_outbox_sent()` 会无条件把任务主状态改回 `succeeded`,形成以下矛盾: - 表格显示“已完成”; - 最新执行记录实际失败; - 同一任务仍有未发送的失败 Outbox; - 点击“重新执行”又被“仍有未发送的结果”拦截。 现场记录 `COL-3dec8b1e10f28954` 已复现:旧结果已发送,最新 `task_failure` 为 `pending`。 ## 做什么 / 不做什么 - 做:历史结果重新上报只更新 Outbox,不覆盖任务最新执行状态。 - 做:重新上报时优先处理任务尚未发送的 Outbox,包括 `task_failure`;没有未发送事件时才重发最新结果。 - 做:发送失败事件成功后,按该事件对应的最新执行恢复任务失败状态,修复已经产生的“假完成”记录。 - 做:重新执行拦截提示明确说明未发送的是结果还是失败信息,并给出恢复路径。 - 做:补充 Repository、事件 Worker 和状态一致性回归测试。 - 不做:不修改 Admin 接口和数据库表结构。 - 不做:不操作 Android 设备,不触发采集、采购或真实下单。 - 不做:不自动删除历史结果或失败记录。 ## 怎么做 - 在 `client/src/task_repository.py` 中区分“首次结果提交成功”和“历史事件重新上报成功”的状态更新语义。 - 新增按任务选择待上报事件的方法:优先返回未发送事件;没有时返回最新结果事件。 - 失败事件发送成功时,只在它属于最新一次执行时恢复任务的失败状态,避免旧失败覆盖新结果。 - 在 `client/src/pdd_ui_event.py` 中让重新上报 Worker 使用新的事件选择和完成方法。 - 调整重新执行校验文案,并同步 `docs/client/03-data-model.md`、`docs/client/05-ui-specification.md` 中的稳定规则。 - 预计修改测试:`client/test/test_task_repository.py`、`client/test/test_pdd_ui_event.py`。 ## 验收标准 - [ ] 重发旧的已发送采集结果不会把最新失败任务改成“已完成”。 - [ ] 存在待发送 `task_failure` 时,“重新上报”优先发送该失败事件。 - [ ] 最新失败事件上报成功后,任务保持或恢复为该次执行对应的失败状态。 - [ ] 旧失败事件上报成功不会覆盖更新一次执行产生的成功状态。 - [ ] 没有未发送事件时,仍能重发最新采集或采购结果。 - [ ] 重新执行遇到未发送失败事件时显示准确中文提示。 - [ ] 不创建重复 Outbox,不修改 Admin 接口,不调用 Android 自动化。 - [ ] Client 完整自动测试通过。 ## 怎么验证 从 `client/` 目录执行: ```powershell C:/Python310/python.exe -m unittest discover -s test -p "test_task_repository.py" C:/Python310/python.exe -m unittest discover -s test -p "test_pdd_ui_event.py" C:/Python310/python.exe -m unittest discover -s test -p "test_*.py" ``` 使用临时 SQLite 构造“旧结果已发送 → 新执行失败未上报 → 手工重新上报”的时间线,核对任务状态、事件选择和幂等键。真实 Admin 联调单独记录,不操作手机。 ## 风险和回退 - 风险:错误恢复任务状态可能让旧失败覆盖新结果;必须同时校验事件的 `attempt_id` 与最新 `task_runs`。 - 风险:重新上报语义从“仅结果”扩展为“优先未发送事件”,需要保持原幂等键,避免 Admin 重复落库。 - 回退:按本工单提交整体回退;数据库无结构迁移,历史 Outbox 数据保持不变。
Author
Owner

实施完成,等待用户验收

已完成以下修复:

  • 重新上报优先选择最早一条尚未发送的 Outbox,并支持 task_failure。
  • Worker 按事件类型调用 submit_result 或 submit_failure,复用原始负载和幂等键。
  • 已发送历史结果再次上报时不再修改任务主状态。
  • 只有与最新执行记录 attempt_id 一致的事件才能更新任务状态。
  • 最新失败信息上报成功后可修复旧版本产生的“假完成”状态;旧失败不会覆盖新成功。
  • 重新执行拦截提示会明确区分未发送结果和未上报失败信息。

验证结果

  • Repository 专项:17 项通过
  • PDD UI 事件专项:37 项通过
  • Client 完整回归:Ran 235 tests in 9.777s,OK
  • PyQt5 离屏窗口冒烟:OK
  • 未调用 Android,未修改 Admin 接口和数据库表结构

最初从仓库根目录执行模块测试时因项目 src 导入路径不成立而未加载测试,已把工单验证命令更正为从 client/ 目录执行;正确命令均通过。

提交与归档

  • 实现提交:077cba6 fix: 修复重新上报任务状态不一致 (#91)
  • 归档提交:3bfaf44 docs: 归档任务 #91
  • 归档:docs/task/91-修复重新上报任务状态不一致.md

现场验收

升级并重启 Client 后:

  1. 勾选 COL-3dec8b1e10f28954,点击“重新上报”。
  2. 本次应优先上报待发送的失败信息,而不是旧采集结果。
  3. Admin 接收成功后,表格状态应从错误的“已完成”恢复为“失败”。
  4. 再次勾选该任务点击“重新执行”,应不再提示存在未发送数据。

现场数据库没有由开发过程直接修改。工单保持开启,#1、#2 清单保持未完成,等待用户验收。

## 实施完成,等待用户验收 已完成以下修复: - 重新上报优先选择最早一条尚未发送的 Outbox,并支持 `task_failure`。 - Worker 按事件类型调用 `submit_result` 或 `submit_failure`,复用原始负载和幂等键。 - 已发送历史结果再次上报时不再修改任务主状态。 - 只有与最新执行记录 `attempt_id` 一致的事件才能更新任务状态。 - 最新失败信息上报成功后可修复旧版本产生的“假完成”状态;旧失败不会覆盖新成功。 - 重新执行拦截提示会明确区分未发送结果和未上报失败信息。 ### 验证结果 - Repository 专项:17 项通过 - PDD UI 事件专项:37 项通过 - Client 完整回归:`Ran 235 tests in 9.777s`,`OK` - PyQt5 离屏窗口冒烟:`OK` - 未调用 Android,未修改 Admin 接口和数据库表结构 最初从仓库根目录执行模块测试时因项目 `src` 导入路径不成立而未加载测试,已把工单验证命令更正为从 `client/` 目录执行;正确命令均通过。 ### 提交与归档 - 实现提交:`077cba6` `fix: 修复重新上报任务状态不一致 (#91)` - 归档提交:`3bfaf44` `docs: 归档任务 #91` - 归档:`docs/task/91-修复重新上报任务状态不一致.md` ### 现场验收 升级并重启 Client 后: 1. 勾选 `COL-3dec8b1e10f28954`,点击“重新上报”。 2. 本次应优先上报待发送的失败信息,而不是旧采集结果。 3. Admin 接收成功后,表格状态应从错误的“已完成”恢复为“失败”。 4. 再次勾选该任务点击“重新执行”,应不再提示存在未发送数据。 现场数据库没有由开发过程直接修改。工单保持开启,#1、#2 清单保持未完成,等待用户验收。
Author
Owner

用户已于 2026-08-11 明确验收通过。

  • 本地归档状态已更新为“已完成,用户验收通过”
  • 验收记录提交:eca9289
  • 本工单按项目流程关闭
用户已于 2026-08-11 明确验收通过。 - 本地归档状态已更新为“已完成,用户验收通过” - 验收记录提交:`eca9289` - 本工单按项目流程关闭
ila closed this issue 2026-08-11 10:58:19 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#91