package mysql import ( "context" "database/sql" "encoding/json" "fmt" "git.yuntuo.hk/k2safe/orbit/internal/fault" core "git.yuntuo.hk/k2safe/orbit/model" "git.yuntuo.hk/k2safe/orbit/platform/auth" "git.yuntuo.hk/k2safe/orbit/pulse/service" ) // CancelTask 将取消意图与开始授权串行化;已开始的尝试仍须确认结果或到期核查。 func (s *TaskStore) CancelTask(ctx context.Context, token auth.Token, id core.ID, key string, in service.CancelInput) (service.CancelResult, error) { var out service.CancelResult err := s.transaction(ctx, token, "tasks:cancel", func(tx *sql.Tx, p auth.Permissions) error { view, err := readTask(ctx, tx, token.NamespaceID, id, false) if err != nil { return err } if !p.AllowsQueue(view.QueueID) { return fault.NotFound } identity, cached, err := reserveIdentity(ctx, tx, token.NamespaceID, "task.cancel", string(id), key, "task", id, in) if err != nil { return err } if cached != nil { if err := json.Unmarshal(cached, &out); err != nil { return err } out.Deduplicated = true return nil } // 应用额度 → 队列 → 任务 → 尝试 → 许可;取消不获取 Worker 会话锁。 if _, _, err := lockQueue(ctx, tx, token.NamespaceID, view.QueueID); err != nil { return err } task, err := readExecutionTask(ctx, tx, token.NamespaceID, id) if err != nil { return err } view = task.view if view.Revision != in.ExpectedRevision || view.State.Terminal() || view.CancelRequestedAt != nil { return fault.Conflict } var owner sql.NullString if err := tx.QueryRowContext(ctx, "SELECT owner_kind FROM pulse_tasks WHERE namespace_id=? AND id=?", token.NamespaceID, id).Scan(&owner); err != nil { return err } if owner.Valid && owner.String != "schedule" { return fault.Conflict } now, err := dbNow(ctx, tx) if err != nil { return err } out.Task, err = cancelExecutionTask(ctx, tx, token.NamespaceID, task, now, "CANCEL_REQUESTED") if err != nil { return err } if err := appendAudit(ctx, tx, token, identity, id, "task", "task.cancel", in.Reason, map[string]any{"state": view.State, "revision": fmt.Sprint(view.Revision)}, map[string]any{"state": out.Task.State, "revision": fmt.Sprint(out.Task.Revision), "cancel_requested_at": now}); err != nil { return err } return saveIdentity(ctx, tx, token.NamespaceID, identity, out) }) return out, err }