fix(generation): 修复生成任务状态机缺失导致状态永不更新的问题 #198

Merged
xiaoxia merged 2 commits from fix/generation-task-status into develop 2026-07-09 15:42:43 +08:00
Owner

问题根因

generate_video Celery 任务完全没有状态更新逻辑:

  • 任务开始执行时,不更新 GenerationTask 状态为 running
  • 任务成功时,不更新状态为 completed
  • 任务失败时,不更新状态为 failed
  • GenerationTask 领域模型缺少 mark_processing/mark_completed/mark_failed 方法

结果:任务状态永远停留在 pending,前端查询时一直显示"生成中"或超时显示失败,即使视频实际上已经生成成功了。

修复方案

1. GenerationTask 领域模型增加完整状态机

  • 新增 TERMINAL_STATUSES 终态集合
  • 新增 _VALID_TRANSITIONS 合法状态转换表
  • 新增 transition_to() 通用状态转换方法(含合法性校验)
  • 新增 mark_processing() — pending → running,设置 started_at
  • 新增 mark_completed(result_count) — running → completed,设置 completed_at/progress/result_count
  • 新增 mark_failed(error_message) — pending/running → failed,设置 error_message/completed_at
  • 新增 mark_cancelled() — pending/running → cancelled
  • 新增 mark_pending_from_failed() — failed → pending(用于重试)
  • 新增 is_terminal / is_completed / is_failed / is_running 属性

状态机

  pending → running → completed
              ↘ failed → pending (重试)
       ↘ cancelled

状态转换有严格的合法性校验,防止非法转换(如 completed → running)。

2. generate_video Celery 任务增加状态更新

  • 新增 _update_task_status() 辅助函数:独立 session + 异常隔离
  • 任务开始时:调用 mark_processing() 更新为 running
  • 任务成功时:调用 mark_completed() 更新为 completed,传入视频数量
  • 任务失败时:在 except 块中调用 mark_failed() 记录错误信息
  • _create_video_record_and_dedup 返回值改为 int,方便统计成功数量

状态更新使用独立数据库 session,且所有状态更新操作都包裹在 try/except 中,确保不会因为状态更新失败导致整个任务异常(参考 edit_plan_generation.py 的模式)。

3. 新增状态机单元测试

新增 tests/unit/test_generation_task_status.py,覆盖 42 个测试用例:

  • 初始状态验证
  • mark_processing 正常/异常路径
  • mark_completed 正常/异常路径
  • mark_failed 正常/异常路径
  • mark_cancelled 正常/异常路径
  • mark_pending_from_failed 重试路径
  • transition_to 通用方法
  • 完整流转路径(成功、失败、重试、取消)

影响范围

文件 变更类型 说明
packages/domain/generation_task.py 修改 新增状态机方法
apps/worker/worker_app/tasks/generation.py 修改 Celery 任务状态更新
tests/unit/test_generation_task_status.py 新增 状态机单元测试

验证方式

  • 42 个状态机单元测试全部通过
  • 现有 8 个生成相关测试全部通过
  • 现有 15 个生成 API 集成测试全部通过
  • 现有 6 个编辑计划 worker 失败测试全部通过
  • 现有 25 个生成视频管理测试全部通过

参考实现

状态机模式参考自 packages/domain/tts_job.py
Celery 任务状态更新参考自 apps/worker/worker_app/tasks/edit_plan_generation.py

## 问题根因 `generate_video` Celery 任务完全没有状态更新逻辑: - 任务开始执行时,不更新 GenerationTask 状态为 running - 任务成功时,不更新状态为 completed - 任务失败时,不更新状态为 failed - GenerationTask 领域模型缺少 mark_processing/mark_completed/mark_failed 方法 **结果**:任务状态永远停留在 pending,前端查询时一直显示"生成中"或超时显示失败,即使视频实际上已经生成成功了。 ## 修复方案 ### 1. GenerationTask 领域模型增加完整状态机 - 新增 `TERMINAL_STATUSES` 终态集合 - 新增 `_VALID_TRANSITIONS` 合法状态转换表 - 新增 `transition_to()` 通用状态转换方法(含合法性校验) - 新增 `mark_processing()` — pending → running,设置 started_at - 新增 `mark_completed(result_count)` — running → completed,设置 completed_at/progress/result_count - 新增 `mark_failed(error_message)` — pending/running → failed,设置 error_message/completed_at - 新增 `mark_cancelled()` — pending/running → cancelled - 新增 `mark_pending_from_failed()` — failed → pending(用于重试) - 新增 `is_terminal` / `is_completed` / `is_failed` / `is_running` 属性 **状态机**: ``` pending → running → completed ↘ failed → pending (重试) ↘ cancelled ``` 状态转换有严格的合法性校验,防止非法转换(如 completed → running)。 ### 2. generate_video Celery 任务增加状态更新 - 新增 `_update_task_status()` 辅助函数:独立 session + 异常隔离 - **任务开始时**:调用 `mark_processing()` 更新为 running - **任务成功时**:调用 `mark_completed()` 更新为 completed,传入视频数量 - **任务失败时**:在 except 块中调用 `mark_failed()` 记录错误信息 - `_create_video_record_and_dedup` 返回值改为 int,方便统计成功数量 状态更新使用独立数据库 session,且所有状态更新操作都包裹在 try/except 中,确保不会因为状态更新失败导致整个任务异常(参考 edit_plan_generation.py 的模式)。 ### 3. 新增状态机单元测试 新增 `tests/unit/test_generation_task_status.py`,覆盖 42 个测试用例: - 初始状态验证 - mark_processing 正常/异常路径 - mark_completed 正常/异常路径 - mark_failed 正常/异常路径 - mark_cancelled 正常/异常路径 - mark_pending_from_failed 重试路径 - transition_to 通用方法 - 完整流转路径(成功、失败、重试、取消) ## 影响范围 | 文件 | 变更类型 | 说明 | |------|---------|------| | `packages/domain/generation_task.py` | 修改 | 新增状态机方法 | | `apps/worker/worker_app/tasks/generation.py` | 修改 | Celery 任务状态更新 | | `tests/unit/test_generation_task_status.py` | 新增 | 状态机单元测试 | ## 验证方式 - ✅ 42 个状态机单元测试全部通过 - ✅ 现有 8 个生成相关测试全部通过 - ✅ 现有 15 个生成 API 集成测试全部通过 - ✅ 现有 6 个编辑计划 worker 失败测试全部通过 - ✅ 现有 25 个生成视频管理测试全部通过 ## 参考实现 状态机模式参考自 `packages/domain/tts_job.py` Celery 任务状态更新参考自 `apps/worker/worker_app/tasks/edit_plan_generation.py`
xiaoxia added 1 commit 2026-07-09 15:34:58 +08:00
fix(generation): 修复生成任务状态机缺失导致状态永不更新的问题
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 8s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m38s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
f5f54b98b6
## 问题根因
generate_video Celery 任务完全没有状态更新逻辑:
- 任务开始执行时,不更新 GenerationTask 状态为 running
- 任务成功时,不更新状态为 completed
- 任务失败时,不更新状态为 failed
- GenerationTask 领域模型缺少 mark_processing/mark_completed/mark_failed 方法

结果:任务状态永远停留在 pending,前端查询时一直显示"生成中"或超时显示失败,即使视频实际上已经生成成功了。

## 修复方案

### 1. GenerationTask 领域模型增加完整状态机
- 新增 TERMINAL_STATUSES 终态集合
- 新增 _VALID_TRANSITIONS 合法状态转换表
- 新增 transition_to() 通用状态转换方法(含合法性校验)
- 新增 mark_processing() — pending → running,设置 started_at
- 新增 mark_completed(result_count) — running → completed,设置 completed_at/progress/result_count
- 新增 mark_failed(error_message) — pending/running → failed,设置 error_message/completed_at
- 新增 mark_cancelled() — pending/running → cancelled
- 新增 mark_pending_from_failed() — failed → pending(用于重试)
- 新增 is_terminal/is_completed/is_failed/is_running 属性

状态机:
  pending → running → completed
              ↘ failed → pending (重试)
       ↘ cancelled

### 2. generate_video Celery 任务增加状态更新
- 新增 _update_task_status() 辅助函数:独立 session + 异常隔离
- 任务开始时:调用 mark_processing() 更新为 running
- 任务成功时:调用 mark_completed() 更新为 completed,传入视频数量
- 任务失败时:在 except 块中调用 mark_failed() 记录错误信息
- _create_video_record_and_dedup 返回值改为 int,方便统计成功数量

状态更新使用独立数据库 session,且所有状态更新操作都包裹在 try/except 中,确保不会因为状态更新失败导致整个任务异常。

### 3. 新增状态机单元测试
新增 tests/unit/test_generation_task_status.py,覆盖 42 个测试用例:
- 初始状态验证
- mark_processing 正常/异常路径
- mark_completed 正常/异常路径
- mark_failed 正常/异常路径
- mark_cancelled 正常/异常路径
- mark_pending_from_failed 重试路径
- transition_to 通用方法
- 完整流转路径(成功、失败、重试、取消)

## 影响范围
- packages/domain/generation_task.py — 领域模型状态机方法
- apps/worker/worker_app/tasks/generation.py — Celery 任务状态更新
- tests/unit/test_generation_task_status.py — 新增单元测试

## 验证方式
- 42 个状态机单元测试全部通过
- 现有 8 个生成相关测试全部通过
- 现有 15 个生成 API 集成测试全部通过
- 现有 6 个编辑计划 worker 失败测试全部通过
- 现有 25 个生成视频管理测试全部通过
xiaoxia added 1 commit 2026-07-09 15:37:03 +08:00
style(domain): format generation_task.py with black
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Successful in 1m0s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 1m31s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
4437a08d4f
xiaoxia merged commit 5ec71f5e1e into develop 2026-07-09 15:42:43 +08:00
Sign in to join this conversation.