120 lines
3.6 KiB
Go
120 lines
3.6 KiB
Go
// Package handler provides HTTP handlers for various endpoints.
|
||
package handler
|
||
|
||
import (
|
||
"net/http"
|
||
"time"
|
||
|
||
"modelRT/database"
|
||
"modelRT/logger"
|
||
"modelRT/network"
|
||
"modelRT/orm"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/gofrs/uuid"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// AsyncTaskCancelHandler handles cancellation of an async task
|
||
// @Summary 取消异步任务
|
||
// @Description 取消指定ID的异步任务(如果任务尚未开始执行)
|
||
// @Tags AsyncTask
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param task_id path string true "任务ID"
|
||
// @Success 200 {object} network.SuccessResponse "任务取消成功"
|
||
// @Failure 400 {object} network.FailureResponse "请求参数错误或任务无法取消"
|
||
// @Failure 404 {object} network.FailureResponse "任务不存在"
|
||
// @Failure 500 {object} network.FailureResponse "服务器内部错误"
|
||
// @Router /task/async/{task_id}/cancel [post]
|
||
func AsyncTaskCancelHandler(c *gin.Context) {
|
||
ctx := c.Request.Context()
|
||
|
||
// Parse task ID from path parameter
|
||
taskIDStr := c.Param("task_id")
|
||
if taskIDStr == "" {
|
||
logger.Error(ctx, "task_id parameter is required")
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusBadRequest,
|
||
Msg: "task_id parameter is required",
|
||
})
|
||
return
|
||
}
|
||
|
||
taskID, err := uuid.FromString(taskIDStr)
|
||
if err != nil {
|
||
logger.Error(ctx, "invalid task ID format", "task_id", taskIDStr, "error", err)
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusBadRequest,
|
||
Msg: "invalid task ID format",
|
||
})
|
||
return
|
||
}
|
||
|
||
pgClient := database.GetPostgresDBClient()
|
||
if pgClient == nil {
|
||
logger.Error(ctx, "database connection not found in context")
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusInternalServerError,
|
||
Msg: "database connection error",
|
||
})
|
||
return
|
||
}
|
||
|
||
// Query task from database
|
||
asyncTask, err := database.GetAsyncTaskByID(ctx, pgClient, taskID)
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
logger.Error(ctx, "async task not found", "task_id", taskID)
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusNotFound,
|
||
Msg: "task not found",
|
||
})
|
||
return
|
||
}
|
||
logger.Error(ctx, "failed to query async task from database", "error", err)
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusInternalServerError,
|
||
Msg: "failed to query task",
|
||
})
|
||
return
|
||
}
|
||
|
||
// Check if task can be cancelled (only SUBMITTED tasks can be cancelled)
|
||
if asyncTask.Status != orm.AsyncTaskStatusSubmitted {
|
||
logger.Error(ctx, "task cannot be cancelled", "task_id", taskID, "status", asyncTask.Status)
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusBadRequest,
|
||
Msg: "task cannot be cancelled (already running or completed)",
|
||
})
|
||
return
|
||
}
|
||
|
||
// Update task status to failed with cancellation reason
|
||
timestamp := time.Now().Unix()
|
||
err = database.FailAsyncTask(ctx, pgClient, taskID, timestamp)
|
||
if err != nil {
|
||
logger.Error(ctx, "failed to cancel async task", "task_id", taskID, "error", err)
|
||
c.JSON(http.StatusOK, network.FailureResponse{
|
||
Code: http.StatusInternalServerError,
|
||
Msg: "failed to cancel task",
|
||
})
|
||
return
|
||
}
|
||
|
||
// Update task result with cancellation error
|
||
err = database.UpdateAsyncTaskResultWithError(ctx, pgClient, taskID, 40003, "task cancelled by user", orm.JSONMap{
|
||
"cancelled_at": timestamp,
|
||
"cancelled_by": "user",
|
||
})
|
||
if err != nil {
|
||
logger.Error(ctx, "failed to update task result with cancellation error", "task_id", taskID, "error", err)
|
||
// Continue anyway since task is already marked as failed
|
||
}
|
||
|
||
c.JSON(http.StatusOK, network.SuccessResponse{
|
||
Code: 2000,
|
||
Msg: "task cancelled successfully",
|
||
})
|
||
}
|