feat(tenant): business-date-scope monitor lease lanes and authorization-failure cancellation

Add an optional lane filter to the monitor task lease so callers can pull
a specific lane (e.g. high) and scope authorization-failure cancellation
to the failing task's business date, so a challenge on one day no longer
cancels queued tasks for another day. Monitor authorization-failure
cancellation now requires a business date and no-ops without one. Also
stop writing the nonexistent desktop_tasks.completed_at column when
canceling queued tasks for an authorization failure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-22 23:57:10 +08:00
parent 7988a65018
commit fc7495aba0
4 changed files with 141 additions and 19 deletions
@@ -146,6 +146,11 @@ func loadQueuedDesktopAuthorizationFailureCandidates(
tx pgx.Tx,
task *repository.DesktopTask,
) ([]queuedDesktopAuthorizationFailureCandidate, error) {
businessDate := desktopAuthorizationTaskBusinessDate(task)
if task != nil && task.Kind == "monitor" && businessDate == "" {
return nil, nil
}
rows, err := tx.Query(ctx, `
SELECT desktop_id, monitor_task_id
FROM desktop_tasks
@@ -157,9 +162,19 @@ func loadQueuedDesktopAuthorizationFailureCandidates(
AND (kind = 'monitor' OR target_account_id = $5)
AND platform_id = $6
AND desktop_id <> $7
AND (
kind <> 'monitor'
OR COALESCE(
NULLIF(payload ->> 'business_date', ''),
NULLIF(payload ->> 'businessDate', ''),
NULLIF(payload ->> 'metric_date', ''),
NULLIF(payload ->> 'date', ''),
''
) = $8
)
ORDER BY COALESCE(enqueued_at, created_at) ASC, created_at ASC, desktop_id ASC
FOR UPDATE SKIP LOCKED
`, task.TenantID, task.WorkspaceID, task.Kind, task.TargetClientID, task.TargetAccountID, task.Platform, task.DesktopID)
`, task.TenantID, task.WorkspaceID, task.Kind, task.TargetClientID, task.TargetAccountID, task.Platform, task.DesktopID, businessDate)
if err != nil {
return nil, response.ErrInternal(50121, "desktop_task_authorization_failure_query_failed", "failed to select queued desktop tasks blocked by authorization failure")
}
@@ -186,6 +201,19 @@ func loadQueuedDesktopAuthorizationFailureCandidates(
return candidates, nil
}
func desktopAuthorizationTaskBusinessDate(task *repository.DesktopTask) string {
if task == nil || len(task.Payload) == 0 {
return ""
}
payload := unmarshalJSONObject(task.Payload)
for _, key := range []string{"business_date", "businessDate", "metric_date", "date"} {
if value := desktopAuthorizationFailureString(payload[key]); value != "" {
return value
}
}
return ""
}
func finishQueuedDesktopTaskForAuthorizationFailure(
ctx context.Context,
tx pgx.Tx,
@@ -193,19 +221,7 @@ func finishQueuedDesktopTaskForAuthorizationFailure(
status string,
errorJSON []byte,
) (*repository.DesktopTask, error) {
row := tx.QueryRow(ctx, `
UPDATE desktop_tasks AS t
SET status = $2,
result = NULL,
error = $3,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
completed_at = NOW(),
updated_at = NOW()
WHERE desktop_id = $1
AND status = 'queued'
RETURNING `+desktopTaskRepositoryReturningColumns,
row := tx.QueryRow(ctx, finishQueuedDesktopTaskForAuthorizationFailureSQL(),
desktopID,
status,
errorJSON,
@@ -220,6 +236,21 @@ func finishQueuedDesktopTaskForAuthorizationFailure(
return updated, nil
}
func finishQueuedDesktopTaskForAuthorizationFailureSQL() string {
return `
UPDATE desktop_tasks AS t
SET status = $2,
result = NULL,
error = $3,
active_attempt_id = NULL,
lease_token_hash = NULL,
lease_expires_at = NULL,
updated_at = NOW()
WHERE desktop_id = $1
AND status = 'queued'
RETURNING ` + desktopTaskRepositoryReturningColumns
}
func desktopAuthorizationFailureDispositionFromPayload(
task *repository.DesktopTask,
payload map[string]any,
@@ -107,6 +107,7 @@ type LeaseDesktopTaskRequest struct {
TaskID *string `json:"task_id"`
Kind *string `json:"kind" binding:"omitempty,oneof=publish monitor"`
PlatformIDs []string `json:"platform_ids"`
Lanes []string `json:"lanes"`
}
type LeaseDesktopTaskResponse struct {
@@ -216,6 +217,7 @@ func (s *DesktopTaskService) Lease(ctx context.Context, client *repository.Deskt
LeaseTokenHash: tokenHash,
}
eligiblePlatformIDs := normalizeDesktopTaskLeasePlatformIDs(req.PlatformIDs)
eligibleLanes := normalizeDesktopTaskLeaseLanes(req.Lanes)
if s.logger != nil {
fields := []zap.Field{
@@ -235,7 +237,7 @@ func (s *DesktopTaskService) Lease(ctx context.Context, client *repository.Deskt
case taskID != nil:
task, err = s.leaseQueuedDesktopTaskByID(ctx, client, *taskID, leaseParams)
case req.Kind != nil && strings.TrimSpace(*req.Kind) == "monitor":
task, err = s.leaseNextQueuedMonitorTask(ctx, client, leaseParams, eligiblePlatformIDs)
task, err = s.leaseNextQueuedMonitorTask(ctx, client, leaseParams, eligiblePlatformIDs, eligibleLanes)
case req.Kind != nil && strings.TrimSpace(*req.Kind) == "publish":
task, err = s.leaseNextQueuedPublishTask(ctx, client, leaseParams)
default:
@@ -523,6 +525,7 @@ func (s *DesktopTaskService) leaseNextQueuedMonitorTask(
client *repository.DesktopClient,
params repository.DesktopTaskLeaseParams,
eligiblePlatformIDs []string,
eligibleLanes []string,
) (*repository.DesktopTask, error) {
tx, err := beginDesktopMonitorLeaseTx(ctx, s.pool, client.ID)
if err != nil {
@@ -538,6 +541,7 @@ func (s *DesktopTaskService) leaseNextQueuedMonitorTask(
params.LeaseTokenHash,
maxConcurrentMonitorPlatformsPerDesktopClient,
eligiblePlatformIDs,
eligibleLanes,
)
task, err := scanRepositoryDesktopTask(row)
if err != nil {
@@ -582,10 +586,14 @@ func leaseNextQueuedMonitorTaskSQL() string {
AND dt.platform_id = ca.platform_id
AND dt.kind = 'monitor'
AND dt.status = 'queued'
AND (
COALESCE(array_length($7::text[], 1), 0) = 0
OR dt.platform_id = ANY($7::text[])
)
AND (
COALESCE(array_length($7::text[], 1), 0) = 0
OR dt.platform_id = ANY($7::text[])
)
AND (
COALESCE(array_length($8::text[], 1), 0) = 0
OR dt.lane = ANY($8::text[])
)
WHERE NOT EXISTS (
SELECT 1
FROM desktop_tasks AS active
@@ -701,6 +709,32 @@ func normalizeDesktopTaskLeasePlatformIDs(values []string) []string {
return result
}
func normalizeDesktopTaskLeaseLanes(values []string) []string {
allowed := map[string]struct{}{
"high": {},
"normal": {},
"normal_boosted": {},
"retry": {},
}
result := make([]string, 0, len(values))
seen := make(map[string]struct{}, len(values))
for _, value := range values {
normalized := strings.ToLower(strings.TrimSpace(value))
if _, ok := allowed[normalized]; !ok {
continue
}
if _, exists := seen[normalized]; exists {
continue
}
seen[normalized] = struct{}{}
result = append(result, normalized)
}
if len(result) == 0 {
return nil
}
return result
}
func monitorAccountLeaseLockSQL(alias string) string {
return fmt.Sprintf(`hashtextextended(
concat_ws(
@@ -462,6 +462,7 @@ func TestLeaseNextQueuedMonitorTaskSQLUsesAccountIdentityAndClientSlots(t *testi
"WITH current_accounts AS",
"client_id = $3",
"COALESCE(array_length($7::text[], 1), 0) = 0 OR dt.platform_id = ANY($7::text[])",
"COALESCE(array_length($8::text[], 1), 0) = 0 OR dt.lane = ANY($8::text[])",
"dt.target_account_id = target_account.desktop_id",
"target_account.account_fingerprint",
"target_account.platform_uid",
@@ -502,6 +503,39 @@ func TestNormalizeDesktopTaskLeasePlatformIDs(t *testing.T) {
}
}
func TestNormalizeDesktopTaskLeaseLanes(t *testing.T) {
t.Parallel()
got := normalizeDesktopTaskLeaseLanes([]string{" HIGH ", "normal", "", "high", "unsupported"})
want := []string{"high", "normal"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("normalizeDesktopTaskLeaseLanes() = %#v, want %#v", got, want)
}
if got := normalizeDesktopTaskLeaseLanes([]string{" ", "unsupported"}); got != nil {
t.Fatalf("normalizeDesktopTaskLeaseLanes(blank) = %#v, want nil", got)
}
}
func TestFinishQueuedDesktopTaskForAuthorizationFailureSQLMatchesDesktopTaskSchema(t *testing.T) {
t.Parallel()
normalized := normalizeSQLForDesktopTaskTest(finishQueuedDesktopTaskForAuthorizationFailureSQL())
if strings.Contains(normalized, "completed_at") {
t.Fatalf("authorization cancellation query writes nonexistent desktop_tasks.completed_at: %s", normalized)
}
for _, fragment := range []string{
"SET status = $2",
"active_attempt_id = NULL",
"lease_token_hash = NULL",
"lease_expires_at = NULL",
"updated_at = NOW()",
} {
if !strings.Contains(normalized, fragment) {
t.Fatalf("authorization cancellation query missing %q: %s", fragment, normalized)
}
}
}
func TestLeaseQueuedDesktopTaskByIDSQLUsesAccountIdentityAndClientSlots(t *testing.T) {
t.Parallel()
@@ -647,6 +647,7 @@ func TestMonitorAuthorizationFollowupCancellationIsPlatformScopedAcrossAccounts(
TargetClientID: uuid.New(),
TargetAccountID: uuid.New(),
Platform: "doubao",
Payload: []byte(`{"business_date":"2026-07-22"}`),
}
rows, err := loadQueuedDesktopAuthorizationFailureCandidates(context.Background(), tx, task)
@@ -659,6 +660,10 @@ func TestMonitorAuthorizationFollowupCancellationIsPlatformScopedAcrossAccounts(
assert.Contains(t, query, "AND target_client_id = $4")
assert.Contains(t, query, "AND (kind = 'monitor' OR target_account_id = $5)")
assert.Contains(t, query, "AND platform_id = $6")
assert.Contains(t, query, "COALESCE( NULLIF(payload ->> 'business_date', '')")
assert.Contains(t, query, "= $8")
require.Len(t, tx.queryArgs, 8)
assert.Equal(t, "2026-07-22", tx.queryArgs[7])
assert.Equal(t, "aborted", desktopAuthorizationFollowupTaskStatus("monitor"))
assert.Equal(t, "failed", desktopAuthorizationFollowupTaskStatus("publish"))
assert.Equal(t, "task_canceled", desktopAuthorizationFollowupEventType(&repository.DesktopTask{
@@ -667,6 +672,24 @@ func TestMonitorAuthorizationFollowupCancellationIsPlatformScopedAcrossAccounts(
}))
}
func TestMonitorAuthorizationFollowupCancellationRequiresBusinessDate(t *testing.T) {
tx := &captureDailyMonitorTaskTx{}
task := &repository.DesktopTask{
Kind: "monitor",
TenantID: 77,
WorkspaceID: 88,
TargetClientID: uuid.New(),
TargetAccountID: uuid.New(),
Platform: "doubao",
}
rows, err := loadQueuedDesktopAuthorizationFailureCandidates(context.Background(), tx, task)
require.NoError(t, err)
assert.Empty(t, rows)
assert.False(t, tx.queryCalled)
}
func TestFailRemainingMonitoringTasksAfterFinalAccountChallengeScopesToModelAndClient(t *testing.T) {
targetClientID := uuid.New().String()
completedAt := time.Date(2026, 7, 14, 9, 30, 0, 0, time.UTC)