feat(monitoring): fail same-client queued tasks on desktop authorization failure
Desktop Client Build / Resolve Build Metadata (push) Successful in 44s
Backend CI / Backend (push) Successful in 17m5s
Desktop Client Build / Build Desktop Client (push) Successful in 25m13s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 42s

When a desktop monitoring task fails with a non-retryable authorization failure
(login expired, challenge required, risk control), all pending same-client/same-platform
tasks for the same business day are immediately bulk-failed as non-retryable, avoiding
wasted execution attempts. Adds preflight authorization checks before task execution,
enriches failure payloads with disposition metadata (code, category, retryable flags),
and triggers account health reports on auth state degradation.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 23:50:50 +08:00
parent 5bbbbc5cf1
commit 28633cf570
7 changed files with 940 additions and 118 deletions
@@ -1,11 +1,14 @@
package app
import (
"database/sql"
"encoding/json"
"errors"
"strings"
"testing"
"time"
"github.com/google/uuid"
)
func TestDecideHeartbeatPrimaryLease(t *testing.T) {
@@ -363,6 +366,89 @@ func TestValidateMonitoringTaskResultSubmissionRequiresSourcesForCitationMarkers
}
}
func TestMonitoringTaskReadyForQueuedResultAcceptsDesktopReceivedStatus(t *testing.T) {
if !monitoringTaskReadyForQueuedResult(&monitoringCollectTask{
ExecutionOwner: "desktop_tasks",
Status: "received",
CallbackReceivedAt: sqlNullTimeForTest(),
}) {
t.Fatal("monitoringTaskReadyForQueuedResult() desktop received = false, want true")
}
if !monitoringTaskReadyForQueuedResult(&monitoringCollectTask{
ExecutionOwner: "desktop_tasks",
Status: "pending",
CallbackReceivedAt: sqlNullTimeForTest(),
}) {
t.Fatal("monitoringTaskReadyForQueuedResult() legacy desktop pending callback = false, want true")
}
}
func sqlNullTimeForTest() sql.NullTime {
return sql.NullTime{Time: time.Now(), Valid: true}
}
func TestBuildDesktopMonitorTaskErrorValuePreservesNonRetryableAuthorizationFailure(t *testing.T) {
message := "用户登录态已失效,请重新授权后再试。"
value := buildDesktopMonitorTaskErrorValue(&monitoringCollectTask{
ID: 522,
AIPlatformID: "yuanbao",
}, MonitoringTaskResultRequest{
Status: "failed",
ErrorMessage: &message,
RawResponseJSON: map[string]interface{}{
"runtime_error": map[string]interface{}{
"code": "desktop_account_auth_expired",
"message": message,
"retryable": false,
"failure_category": "ai_platform_authorization",
},
},
})
if value["code"] != "desktop_account_auth_expired" {
t.Fatalf("error code = %v, want desktop_account_auth_expired", value["code"])
}
if value["retryable"] != false {
t.Fatalf("retryable = %v, want false", value["retryable"])
}
if value["failure_category"] != "ai_platform_authorization" {
t.Fatalf("failure_category = %v, want ai_platform_authorization", value["failure_category"])
}
}
func TestMonitoringTaskFailureDispositionDetectsAuthorizationFailureFromMessage(t *testing.T) {
message := "登录态已失效,请重新授权后再试。"
got := monitoringTaskFailureDispositionFromRequest(MonitoringTaskResultRequest{
Status: "failed",
ErrorMessage: &message,
RawResponseJSON: map[string]interface{}{
"runtime_error": map[string]interface{}{
"message": message,
},
},
})
if !got.NonRetryable {
t.Fatal("NonRetryable = false, want true")
}
if got.Category != "ai_platform_authorization" {
t.Fatalf("Category = %q, want ai_platform_authorization", got.Category)
}
}
func TestMonitoringAuthorizationFailureTargetClientPrefersExplicitTargetClient(t *testing.T) {
targetClientID := uuid.New().String()
task := &monitoringCollectTask{
TargetClientID: sql.NullString{String: targetClientID, Valid: true},
LeasedToExecutor: sql.NullString{String: uuid.New().String(), Valid: true},
}
if got := monitoringAuthorizationFailureTargetClientID(task); got != targetClientID {
t.Fatalf("target client = %q, want %q", got, targetClientID)
}
}
func TestBuildMonitoringRawPayloadQwenIncludesSearchResultsInCitationInputs(t *testing.T) {
searchTitle := "搜索网页结果"