fix(agent): 图片审批 - 修改生成参数时不再因容量检查自锁
审批落库时已经持有存储锁,干跑创建任务又申请同一把锁。互斥锁不能重入,修改图片参数会一直停住,后端测试也会在 20 分钟后超时。
This commit is contained in:
@@ -49,8 +49,10 @@ func (s *Service) updateCloudAgentMediaApproval(repo *repository.Repository, run
|
||||
}
|
||||
// Dry admission uses the same model, ownership and option checks as task
|
||||
// submission, without reserving credits or creating a generation task.
|
||||
// DecideCloudAgentApproval already holds storageMu for this mutation.
|
||||
preparation := &creationTaskPreparation{}
|
||||
req.creationPrepare = preparation
|
||||
req.callerHoldsStorageMu = true
|
||||
task, err := s.CreateTask(run.UserID, req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -101,16 +101,19 @@ const taskLogPayloadLimit = 4000
|
||||
type CreateTaskRequest struct {
|
||||
creationPrepare *creationTaskPreparation
|
||||
admission *taskAdmission
|
||||
ProjectID string `json:"projectId"`
|
||||
Type string `json:"type"`
|
||||
Operation string `json:"operation"`
|
||||
Prompt string `json:"prompt"`
|
||||
Provider string `json:"provider"`
|
||||
Model string `json:"model"`
|
||||
LogicalModelID string `json:"logicalModelId"`
|
||||
Input map[string]any `json:"input"`
|
||||
TraceID string `json:"-"`
|
||||
RequestID string `json:"-"`
|
||||
// callerHoldsStorageMu 只给已经持有 Service.storageMu 的内部调用设置。
|
||||
// 文件容量检查不能再锁一次,否则审批改参数会自锁。
|
||||
callerHoldsStorageMu bool
|
||||
ProjectID string `json:"projectId"`
|
||||
Type string `json:"type"`
|
||||
Operation string `json:"operation"`
|
||||
Prompt string `json:"prompt"`
|
||||
Provider string `json:"provider"`
|
||||
Model string `json:"model"`
|
||||
LogicalModelID string `json:"logicalModelId"`
|
||||
Input map[string]any `json:"input"`
|
||||
TraceID string `json:"-"`
|
||||
RequestID string `json:"-"`
|
||||
}
|
||||
|
||||
type TaskListOptions struct {
|
||||
|
||||
@@ -119,8 +119,15 @@ func (s *Service) CreateTask(userID string, req CreateTaskRequest) (*model.Task,
|
||||
return nil, BadAuthRequest(fmt.Sprintf("同时排队或运行的任务最多 %d 个,请等待已有任务完成", policy.Task.ActiveTaskLimit))
|
||||
}
|
||||
// 媒体任务在扣费和调用上游前确认账号文件容量,避免容量已满仍然计费却无法回存产物。
|
||||
if err := s.requireStoredFileCapacityForTask(userID, taskType, policy); err != nil {
|
||||
return nil, err
|
||||
// 调用方已持锁时走不加锁的版本;这里不能再抢同一把 storageMu。
|
||||
var capacityErr error
|
||||
if req.callerHoldsStorageMu {
|
||||
capacityErr = s.requireStoredFileCapacityWhileLocked(userID, taskType, policy)
|
||||
} else {
|
||||
capacityErr = s.requireStoredFileCapacityForTask(userID, taskType, policy)
|
||||
}
|
||||
if capacityErr != nil {
|
||||
return nil, capacityErr
|
||||
}
|
||||
task := model.Task{ID: newID(), UserID: userID, TraceID: req.TraceID, RequestID: req.RequestID, ProjectID: req.ProjectID, Type: taskType, Status: model.TaskStatusQueued, Stage: "等待队列调度", Progress: 5, Prompt: prompt, Operation: req.Operation, Provider: req.Provider, Model: req.Model}
|
||||
if req.admission != nil {
|
||||
|
||||
@@ -20,6 +20,15 @@ func taskTypeProducesStoredFile(taskType string) bool {
|
||||
// 账号文件容量此前只在产物回存时校验,上游调用已经发出并扣费,失败只能表现为
|
||||
// 媒体无法入库。生成任务必须在扣费前确认账号还有可用容量,容量已满时直接拒绝。
|
||||
func (s *Service) requireStoredFileCapacityForTask(userID string, taskType string, policy RuntimePolicySetting) error {
|
||||
s.storageMu.Lock()
|
||||
defer s.storageMu.Unlock()
|
||||
return s.requireStoredFileCapacityWhileLocked(userID, taskType, policy)
|
||||
}
|
||||
|
||||
// requireStoredFileCapacityWhileLocked 与上面相同,但调用方必须已经持有 storageMu。
|
||||
// sync.Mutex 不可重入;审批改参数的干跑 admission 发生在 DecideCloudAgentApproval
|
||||
// 的临界区内,再次加锁会把测试和线上审批一起卡死。
|
||||
func (s *Service) requireStoredFileCapacityWhileLocked(userID string, taskType string, policy RuntimePolicySetting) error {
|
||||
if !taskTypeProducesStoredFile(taskType) {
|
||||
return nil
|
||||
}
|
||||
@@ -27,8 +36,6 @@ func (s *Service) requireStoredFileCapacityForTask(userID string, taskType strin
|
||||
if storedLimit <= 0 {
|
||||
return nil
|
||||
}
|
||||
s.storageMu.Lock()
|
||||
defer s.storageMu.Unlock()
|
||||
storedBytes, err := s.repo.UserStoredFileBytes(userID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user