feat(monitoring): dispatch monitoring tasks to desktop via AMQP outbox

Replace SSE /desktop/events with priority AMQP dispatch for monitoring
runs, and add phase1/phase2 infrastructure so desktop workers can lease,
resume, report, skip, and cancel monitoring tasks over the existing
dispatch WebSocket.

- Add monitoring collect outbox worker and phase2 desktop task fields
- Add /desktop/monitoring/tasks/{lease,resume,result,skip,cancel} routes
- Introduce execution-devtools and network-observer on desktop runtime
- Refactor runtime-controller, LoginView, and doubao adapter for the new flow
- Add channelName column to tracking views

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 00:24:21 +08:00
parent 749b6b99cd
commit 4142c53fa6
57 changed files with 7897 additions and 985 deletions
@@ -22,7 +22,7 @@ SET status = 'aborted',
WHERE desktop_id = $2
AND target_client_id = $3
AND status = 'queued'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type CancelDesktopTaskByClientParams struct {
@@ -55,6 +55,19 @@ func (q *Queries) CancelDesktopTaskByClient(ctx context.Context, arg CancelDeskt
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -70,7 +83,7 @@ SET status = 'aborted',
WHERE desktop_id = $2
AND lease_token_hash = $3
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type CancelDesktopTaskByLeaseParams struct {
@@ -103,6 +116,19 @@ func (q *Queries) CancelDesktopTaskByLease(ctx context.Context, arg CancelDeskto
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -119,7 +145,7 @@ SET status = $1,
WHERE desktop_id = $4
AND lease_token_hash = $5
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type CompleteDesktopTaskParams struct {
@@ -160,6 +186,19 @@ func (q *Queries) CompleteDesktopTask(ctx context.Context, arg CompleteDesktopTa
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -249,7 +288,7 @@ VALUES (
$10,
$11
)
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type CreateDesktopTaskParams struct {
@@ -302,6 +341,19 @@ func (q *Queries) CreateDesktopTask(ctx context.Context, arg CreateDesktopTaskPa
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -359,7 +411,7 @@ SET lease_expires_at = now() + interval '10 minutes',
WHERE desktop_id = $1
AND lease_token_hash = $2
AND status = 'in_progress'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type ExtendDesktopTaskLeaseParams struct {
@@ -391,6 +443,19 @@ func (q *Queries) ExtendDesktopTaskLease(ctx context.Context, arg ExtendDesktopT
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -422,7 +487,7 @@ func (q *Queries) FinishDesktopTaskAttempt(ctx context.Context, arg FinishDeskto
}
const getDesktopTaskByDesktopID = `-- name: GetDesktopTaskByDesktopID :one
SELECT id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
SELECT id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
FROM desktop_tasks
WHERE desktop_id = $1
AND workspace_id = $2
@@ -458,6 +523,19 @@ func (q *Queries) GetDesktopTaskByDesktopID(ctx context.Context, arg GetDesktopT
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -472,7 +550,11 @@ WITH candidate AS (
$4::text IS NULL
OR dt.kind = $4::text
)
ORDER BY dt.created_at ASC, dt.desktop_id ASC
ORDER BY dt.lane_weight DESC,
dt.priority DESC,
COALESCE(dt.enqueued_at, dt.created_at) ASC,
dt.created_at ASC,
dt.desktop_id ASC
LIMIT 1
FOR UPDATE SKIP LOCKED
)
@@ -485,7 +567,7 @@ SET active_attempt_id = $1,
updated_at = now()
FROM candidate
WHERE t.desktop_id = candidate.desktop_id
RETURNING t.id, t.desktop_id, t.job_id, t.tenant_id, t.workspace_id, t.target_account_id, t.target_client_id, t.platform_id, t.kind, t.payload, t.status, t.dedup_key, t.active_attempt_id, t.lease_token_hash, t.lease_expires_at, t.attempts, t.result, t.error, t.created_at, t.updated_at
RETURNING t.id, t.desktop_id, t.job_id, t.tenant_id, t.workspace_id, t.target_account_id, t.target_client_id, t.platform_id, t.kind, t.payload, t.status, t.dedup_key, t.active_attempt_id, t.lease_token_hash, t.lease_expires_at, t.attempts, t.result, t.error, t.created_at, t.updated_at, t.priority, t.lane, t.lane_weight, t.source, t.scheduler_group_key, t.monitor_task_id, t.supersedes_task_id, t.control_flags, t.interrupt_generation, t.started_at, t.interrupted_at, t.interrupt_reason, t.enqueued_at
`
type LeaseNextQueuedDesktopTaskParams struct {
@@ -524,6 +606,19 @@ func (q *Queries) LeaseNextQueuedDesktopTask(ctx context.Context, arg LeaseNextQ
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -539,7 +634,7 @@ SET active_attempt_id = $1,
WHERE desktop_id = $3
AND target_client_id = $4
AND status = 'queued'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type LeaseQueuedDesktopTaskByDesktopIDParams struct {
@@ -578,6 +673,19 @@ func (q *Queries) LeaseQueuedDesktopTaskByDesktopID(ctx context.Context, arg Lea
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -628,7 +736,7 @@ SET status = CASE
WHERE desktop_id = $4
AND workspace_id = $5
AND status = 'unknown'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type ReconcileDesktopTaskParams struct {
@@ -669,6 +777,19 @@ func (q *Queries) ReconcileDesktopTask(ctx context.Context, arg ReconcileDesktop
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -684,7 +805,7 @@ SET status = 'aborted',
WHERE desktop_id = $2
AND workspace_id = $3
AND status = 'queued'
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at
RETURNING id, desktop_id, job_id, tenant_id, workspace_id, target_account_id, target_client_id, platform_id, kind, payload, status, dedup_key, active_attempt_id, lease_token_hash, lease_expires_at, attempts, result, error, created_at, updated_at, priority, lane, lane_weight, source, scheduler_group_key, monitor_task_id, supersedes_task_id, control_flags, interrupt_generation, started_at, interrupted_at, interrupt_reason, enqueued_at
`
type TenantCancelDesktopTaskParams struct {
@@ -717,6 +838,19 @@ func (q *Queries) TenantCancelDesktopTask(ctx context.Context, arg TenantCancelD
&i.Error,
&i.CreatedAt,
&i.UpdatedAt,
&i.Priority,
&i.Lane,
&i.LaneWeight,
&i.Source,
&i.SchedulerGroupKey,
&i.MonitorTaskID,
&i.SupersedesTaskID,
&i.ControlFlags,
&i.InterruptGeneration,
&i.StartedAt,
&i.InterruptedAt,
&i.InterruptReason,
&i.EnqueuedAt,
)
return i, err
}
@@ -8,6 +8,19 @@ import (
"github.com/jackc/pgx/v5/pgtype"
)
type AiPlatform struct {
ID int64 `json:"id"`
AiPlatformID string `json:"ai_platform_id"`
Name string `json:"name"`
ShortName string `json:"short_name"`
AccentColor string `json:"accent_color"`
LoginUrl pgtype.Text `json:"login_url"`
Status string `json:"status"`
SortOrder int32 `json:"sort_order"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type Article struct {
ID int64 `json:"id"`
TenantID int64 `json:"tenant_id"`
@@ -150,26 +163,39 @@ type DesktopPublishJob struct {
}
type DesktopTask struct {
ID int64 `json:"id"`
DesktopID pgtype.UUID `json:"desktop_id"`
JobID pgtype.UUID `json:"job_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
TargetAccountID pgtype.UUID `json:"target_account_id"`
TargetClientID pgtype.UUID `json:"target_client_id"`
PlatformID string `json:"platform_id"`
Kind string `json:"kind"`
Payload []byte `json:"payload"`
Status string `json:"status"`
DedupKey pgtype.Text `json:"dedup_key"`
ActiveAttemptID pgtype.UUID `json:"active_attempt_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
LeaseExpiresAt pgtype.Timestamptz `json:"lease_expires_at"`
Attempts int32 `json:"attempts"`
Result []byte `json:"result"`
Error []byte `json:"error"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
ID int64 `json:"id"`
DesktopID pgtype.UUID `json:"desktop_id"`
JobID pgtype.UUID `json:"job_id"`
TenantID int64 `json:"tenant_id"`
WorkspaceID int64 `json:"workspace_id"`
TargetAccountID pgtype.UUID `json:"target_account_id"`
TargetClientID pgtype.UUID `json:"target_client_id"`
PlatformID string `json:"platform_id"`
Kind string `json:"kind"`
Payload []byte `json:"payload"`
Status string `json:"status"`
DedupKey pgtype.Text `json:"dedup_key"`
ActiveAttemptID pgtype.UUID `json:"active_attempt_id"`
LeaseTokenHash []byte `json:"lease_token_hash"`
LeaseExpiresAt pgtype.Timestamptz `json:"lease_expires_at"`
Attempts int32 `json:"attempts"`
Result []byte `json:"result"`
Error []byte `json:"error"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
Priority int32 `json:"priority"`
Lane string `json:"lane"`
LaneWeight int32 `json:"lane_weight"`
Source string `json:"source"`
SchedulerGroupKey pgtype.Text `json:"scheduler_group_key"`
MonitorTaskID pgtype.Int8 `json:"monitor_task_id"`
SupersedesTaskID pgtype.UUID `json:"supersedes_task_id"`
ControlFlags []byte `json:"control_flags"`
InterruptGeneration int32 `json:"interrupt_generation"`
StartedAt pgtype.Timestamptz `json:"started_at"`
InterruptedAt pgtype.Timestamptz `json:"interrupted_at"`
InterruptReason pgtype.Text `json:"interrupt_reason"`
EnqueuedAt pgtype.Timestamptz `json:"enqueued_at"`
}
type DesktopTaskAttempt struct {