refactor(publish): collapse pending_review/unknown task states into failed
Treat ambiguous terminal states as failures end-to-end: server normalizes unknown desktop task completions and views to failed, drops the pending_review aggregate branch, and remaps pending_review to failed in publish record conversion. admin-web removes the pending_review status option from article list filters, pushes pending_review through the failed tone, and folds lingering publishing/pending entries under the publishing bucket. desktop-client relabels unknown as 发送失败 in PublishManagement/TasksView, rewrites the scaffold adapter result to a proper failed error envelope, and sanitises legacy scaffold-only error messages to a user-friendly note. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -199,6 +199,7 @@ func (s *DesktopTaskService) Complete(ctx context.Context, client *repository.De
|
||||
return nil, response.ErrUnauthorized(40108, "desktop_client_missing", "desktop client context is required")
|
||||
}
|
||||
|
||||
finalStatus := normalizeDesktopTaskTerminalStatus(req.Status)
|
||||
resultJSON, err := marshalOptionalJSON(req.Payload)
|
||||
if err != nil {
|
||||
return nil, response.ErrBadRequest(40086, "invalid_desktop_task_payload", "payload must be serializable")
|
||||
@@ -218,7 +219,7 @@ func (s *DesktopTaskService) Complete(ctx context.Context, client *repository.De
|
||||
previousTask, _ := taskRepo.GetByDesktopID(ctx, desktopID, client.WorkspaceID)
|
||||
previousAttemptID := activeAttemptID(previousTask)
|
||||
|
||||
task, err := taskRepo.Complete(ctx, desktopID, HashDesktopClientToken(strings.TrimSpace(req.LeaseToken)), req.Status, resultJSON, errorJSON)
|
||||
task, err := taskRepo.Complete(ctx, desktopID, HashDesktopClientToken(strings.TrimSpace(req.LeaseToken)), finalStatus, resultJSON, errorJSON)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, response.ErrConflict(40983, "desktop_task_lease_invalid", "desktop task lease token is invalid or expired")
|
||||
@@ -230,7 +231,7 @@ func (s *DesktopTaskService) Complete(ctx context.Context, client *repository.De
|
||||
if finishErr := taskRepo.FinishAttempt(ctx, repository.FinishDesktopTaskAttemptParams{
|
||||
TaskID: task.DesktopID,
|
||||
AttemptID: *previousAttemptID,
|
||||
FinalStatus: &req.Status,
|
||||
FinalStatus: &finalStatus,
|
||||
Error: errorJSON,
|
||||
}); finishErr != nil {
|
||||
s.logWarn("desktop task attempt finish failed after complete", finishErr, zap.String("task_id", task.DesktopID.String()))
|
||||
@@ -614,7 +615,7 @@ func scanDesktopTaskRows(rows pgx.Rows) ([]DesktopTaskView, error) {
|
||||
Platform: platform,
|
||||
Kind: kind,
|
||||
Payload: json.RawMessage(payload),
|
||||
Status: status,
|
||||
Status: normalizeDesktopTaskTerminalStatus(status),
|
||||
DedupKey: dedupKeyText,
|
||||
ActiveAttemptID: activeAttemptIDText,
|
||||
LeaseExpiresAt: leaseExpiresAtValue,
|
||||
@@ -672,7 +673,7 @@ func buildDesktopTaskView(task *repository.DesktopTask) DesktopTaskView {
|
||||
Platform: task.Platform,
|
||||
Kind: task.Kind,
|
||||
Payload: json.RawMessage(task.Payload),
|
||||
Status: task.Status,
|
||||
Status: normalizeDesktopTaskTerminalStatus(task.Status),
|
||||
DedupKey: task.DedupKey,
|
||||
ActiveAttemptID: activeAttemptID,
|
||||
LeaseExpiresAt: task.LeaseExpiresAt,
|
||||
@@ -702,6 +703,15 @@ func literalStringPtr(value string) *string {
|
||||
return &value
|
||||
}
|
||||
|
||||
func normalizeDesktopTaskTerminalStatus(status string) string {
|
||||
switch strings.TrimSpace(status) {
|
||||
case "unknown":
|
||||
return "failed"
|
||||
default:
|
||||
return strings.TrimSpace(status)
|
||||
}
|
||||
}
|
||||
|
||||
func activeAttemptID(task *repository.DesktopTask) *uuid.UUID {
|
||||
if task == nil || task.ActiveAttemptID == nil {
|
||||
return nil
|
||||
|
||||
@@ -1013,15 +1013,9 @@ func aggregatePublishStatuses(statuses []string) string {
|
||||
if counts["success"] == len(statuses) {
|
||||
return "success"
|
||||
}
|
||||
if counts["pending_review"] == len(statuses) {
|
||||
return "pending_review"
|
||||
}
|
||||
if counts["failed"] > 0 && (counts["success"] > 0 || counts["pending_review"] > 0) {
|
||||
if counts["failed"] > 0 && counts["success"] > 0 {
|
||||
return "partial_success"
|
||||
}
|
||||
if counts["pending_review"] > 0 {
|
||||
return "pending_review"
|
||||
}
|
||||
if counts["success"] > 0 {
|
||||
return "success"
|
||||
}
|
||||
@@ -1036,10 +1030,8 @@ func normalizePublishStatus(status string) string {
|
||||
return "publishing"
|
||||
case "success", "published", "publish_success":
|
||||
return "success"
|
||||
case "failed", "publish_failed":
|
||||
case "failed", "publish_failed", "pending_review":
|
||||
return "failed"
|
||||
case "pending_review":
|
||||
return "pending_review"
|
||||
default:
|
||||
return "failed"
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ func desktopTaskToPublishStatus(taskStatus string) string {
|
||||
case "in_progress":
|
||||
return "publishing"
|
||||
case "unknown":
|
||||
return "pending_review"
|
||||
return "failed"
|
||||
case "succeeded":
|
||||
return "success"
|
||||
case "failed", "aborted":
|
||||
|
||||
Reference in New Issue
Block a user