feat(monitoring): scope authorization-failure cancellation to platform across accounts

When a monitor task's final account hits human verification or an
authorization failure, cancel the remaining queued desktop/monitoring
tasks for the whole platform instead of only the same account. Follow-up
tasks are now marked skipped/aborted (not failed) with a
platform_human_verification / platform_authorization_unavailable reason
and a user-facing cancellation message, and emit task_canceled lifecycle
events for monitor kinds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-14 22:00:41 +08:00
parent b0bf9b4299
commit 1fab7b1e5f
4 changed files with 196 additions and 31 deletions
@@ -2683,7 +2683,7 @@ func (s *MonitoringCallbackService) completeLinkedDesktopMonitorTask(
publishDesktopTaskLifecycleEvent(ctx, s.rabbitMQ, s.logger, finalizedTask, "task_completed")
for _, failedTask := range bulkFailure.Tasks {
publishDesktopTaskLifecycleEvent(ctx, s.rabbitMQ, s.logger, failedTask, "task_completed")
publishDesktopTaskLifecycleEvent(ctx, s.rabbitMQ, s.logger, failedTask, desktopAuthorizationFollowupEventType(failedTask))
}
return nil
@@ -3260,13 +3260,6 @@ func (s *MonitoringCallbackService) failRemainingMonitoringTasksForAuthorization
runtimeError := buildDesktopMonitorTaskErrorValue(task, req)
runtimeError["blocked_by_authorization_failure_task_id"] = task.ID
runtimeError["blocked_by_authorization_failure_platform"] = task.AIPlatformID
requestPayloadJSON, err := json.Marshal(map[string]any{
"runtime_error": runtimeError,
"blocked_by_authorization_failure": true,
})
if err != nil {
return 0, response.ErrInternal(50041, "task_payload_encode_failed", "failed to encode monitoring authorization failure payload")
}
message := strings.TrimSpace(optionalStringValue(req.ErrorMessage))
if message == "" {
@@ -3275,6 +3268,18 @@ func (s *MonitoringCallbackService) failRemainingMonitoringTasksForAuthorization
if message == "" {
message = "登录态已失效,任务未执行。"
}
skipReason, cancellationMessage := authorizationFailureFollowupCancellation(disposition.Code, message)
runtimeError["canceled"] = true
runtimeError["cancellation_reason"] = skipReason
runtimeError["source_authorization_failure_message"] = message
runtimeError["message"] = cancellationMessage
requestPayloadJSON, err := json.Marshal(map[string]any{
"runtime_error": runtimeError,
"blocked_by_authorization_failure": true,
})
if err != nil {
return 0, response.ErrInternal(50041, "task_payload_encode_failed", "failed to encode monitoring authorization cancellation payload")
}
executionOwner := strings.TrimSpace(task.ExecutionOwner)
if executionOwner == "" {
executionOwner = "legacy"
@@ -3282,28 +3287,28 @@ func (s *MonitoringCallbackService) failRemainingMonitoringTasksForAuthorization
tag, err := tx.Exec(ctx, `
UPDATE monitoring_collect_tasks
SET status = 'failed',
SET status = 'skipped',
lease_token_hash = NULL,
leased_to_executor = NULL,
leased_at = NULL,
lease_expires_at = NULL,
callback_received_at = NOW(),
completed_at = $7,
skip_reason = NULL,
error_message = $8,
skip_reason = $8,
error_message = $9,
request_payload_json = (
CASE
WHEN request_payload_json IS NULL OR jsonb_typeof(request_payload_json) <> 'object'
THEN '{}'::jsonb
ELSE request_payload_json
END
) || $9::jsonb,
) || $10::jsonb,
updated_at = NOW()
WHERE tenant_id = $1
AND collector_type = $2
AND business_date = $3::date
AND ai_platform_id = $4
AND COALESCE(execution_owner, 'legacy') = $10
AND COALESCE(execution_owner, 'legacy') = $11
AND id <> $5
AND status IN ('pending', 'leased', 'expired')
AND callback_received_at IS NULL
@@ -3311,9 +3316,9 @@ func (s *MonitoringCallbackService) failRemainingMonitoringTasksForAuthorization
target_client_id::text = $6
OR leased_to_executor = $6
)
`, task.TenantID, task.CollectorType, task.BusinessDate.Format("2006-01-02"), task.AIPlatformID, task.ID, targetClientID, completedAt, message, requestPayloadJSON, executionOwner)
`, task.TenantID, task.CollectorType, task.BusinessDate.Format("2006-01-02"), task.AIPlatformID, task.ID, targetClientID, completedAt, skipReason, cancellationMessage, requestPayloadJSON, executionOwner)
if err != nil {
return 0, response.ErrInternal(50041, "task_update_failed", "failed to fail remaining monitoring tasks after authorization failure")
return 0, response.ErrInternal(50041, "task_update_failed", "failed to skip remaining monitoring tasks after authorization failure")
}
return tag.RowsAffected(), nil
}