From ed849efbabe78dd00fe4f3644f0b1a2a4b683e43 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Thu, 16 Jul 2026 09:52:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=9F=E6=88=90=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=8F=96=E6=B6=88=E6=8E=A5=E5=8F=A3=20-=20POST=20/tasks/{task?= =?UTF-8?q?=5Fid}/cancel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增生成任务取消接口: - 支持 pending / running 状态的任务取消 - 取消后状态变为 cancelled,记录取消日志 - 终态(completed/failed/cancelled)不可取消,返回 409 - 权限校验:只能取消自己创建的任务 - 复用领域模型已有的 mark_cancelled 方法 --- apps/api/app/api/routes/generation_tasks.py | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) mode change 100644 => 100755 apps/api/app/api/routes/generation_tasks.py diff --git a/apps/api/app/api/routes/generation_tasks.py b/apps/api/app/api/routes/generation_tasks.py old mode 100644 new mode 100755 index 7f7b3fa60..4f625ec53 --- a/apps/api/app/api/routes/generation_tasks.py +++ b/apps/api/app/api/routes/generation_tasks.py @@ -427,3 +427,53 @@ def retry_generation_task( detail="系统繁忙,请稍后再试", ) from None return _to_generation_task_response(retried) + + +@router.post("/tasks/{task_id}/cancel", response_model=GenerationTaskResponse) +def cancel_generation_task( + task_id: str, + authenticated_user: AuthenticatedUser = Depends(get_current_user), + generation_task_repository: Any = Depends(get_generation_task_repository), +) -> GenerationTaskResponse: + """取消生成任务。 + + 仅 pending / running 状态的任务可取消;取消后状态变为 cancelled。 + 对于已在运行的 Celery 任务,标记为 cancelled 后,worker 在下次检查点会中止执行。 + """ + task = generation_task_repository.get(task_id) + if task is None: + raise HTTPException(status_code=404, detail="Generation task not found") + + # 权限校验 + if task.created_by_user_id and task.created_by_user_id != authenticated_user.user.id: + raise HTTPException(status_code=403, detail="Access denied to this task") + + status_val = task.status.value if hasattr(task.status, "value") else str(task.status) + + # 终态不可取消 + if status_val in ("completed", "failed", "cancelled"): + raise HTTPException( + status_code=409, + detail=f"Cannot cancel task in {status_val} status", + ) + + # 执行取消 + try: + task.mark_cancelled() + task.append_log( + stage="cancelled", + message="用户主动取消任务", + level="INFO", + cancelled_by=authenticated_user.user.id, + ) + generation_task_repository.update(task) + logger.info( + "生成任务已取消: task_id=%s user_id=%s previous_status=%s", + task_id, + authenticated_user.user.id, + status_val, + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) from e + + return _to_generation_task_response(task)