Files
geo/server/internal/tenant/repository/desktop_task_repo.go
T
root 4142c53fa6 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>
2026-04-22 00:24:21 +08:00

377 lines
13 KiB
Go

package repository
import (
"context"
"time"
"github.com/google/uuid"
"github.com/geo-platform/tenant-api/internal/tenant/repository/generated"
)
type DesktopPublishJob struct {
DesktopID uuid.UUID
TenantID int64
WorkspaceID int64
CreatedByUserID int64
Title string
ContentRef []byte
ScheduledAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type CreateDesktopPublishJobParams struct {
DesktopID uuid.UUID
TenantID int64
WorkspaceID int64
CreatedByUserID int64
Title string
ContentRef []byte
ScheduledAt *time.Time
}
type DesktopTask struct {
DesktopID uuid.UUID
JobID uuid.UUID
TenantID int64
WorkspaceID int64
TargetAccountID uuid.UUID
TargetClientID uuid.UUID
Platform string
Kind string
Payload []byte
Status string
Priority int
Lane string
LaneWeight int
Source string
SchedulerGroupKey *string
MonitorTaskID *int64
SupersedesTaskID *uuid.UUID
ControlFlags []byte
InterruptGeneration int
DedupKey *string
ActiveAttemptID *uuid.UUID
LeaseExpiresAt *time.Time
Attempts int
Result []byte
Error []byte
StartedAt *time.Time
InterruptedAt *time.Time
InterruptReason *string
EnqueuedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type CreateDesktopTaskParams struct {
DesktopID uuid.UUID
JobID uuid.UUID
TenantID int64
WorkspaceID int64
TargetAccountID uuid.UUID
TargetClientID uuid.UUID
Platform string
Kind string
Payload []byte
Status string
DedupKey *string
}
type DesktopTaskLeaseParams struct {
AttemptID uuid.UUID
LeaseTokenHash []byte
}
type DesktopTaskAttempt struct {
DesktopID uuid.UUID
TaskID uuid.UUID
ClientID uuid.UUID
StartedAt time.Time
EndedAt *time.Time
FinalStatus *string
Error []byte
CreatedAt time.Time
}
type CreateDesktopTaskAttemptParams struct {
DesktopID uuid.UUID
TaskID uuid.UUID
ClientID uuid.UUID
LeaseTokenHash []byte
}
type FinishDesktopTaskAttemptParams struct {
TaskID uuid.UUID
AttemptID uuid.UUID
FinalStatus *string
Error []byte
}
type DesktopTaskRepository interface {
CreatePublishJob(ctx context.Context, params CreateDesktopPublishJobParams) (*DesktopPublishJob, error)
CreateTask(ctx context.Context, params CreateDesktopTaskParams) (*DesktopTask, error)
GetByDesktopID(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopTask, error)
LeaseNextQueued(ctx context.Context, clientID uuid.UUID, kind *string, params DesktopTaskLeaseParams) (*DesktopTask, error)
LeaseQueuedByDesktopID(ctx context.Context, desktopID, clientID uuid.UUID, params DesktopTaskLeaseParams) (*DesktopTask, error)
ExtendLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte) (*DesktopTask, error)
Complete(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, status string, resultJSON, errorJSON []byte) (*DesktopTask, error)
CancelByLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, errorJSON []byte) (*DesktopTask, error)
CancelByClient(ctx context.Context, desktopID, clientID uuid.UUID, errorJSON []byte) (*DesktopTask, error)
TenantCancel(ctx context.Context, desktopID uuid.UUID, workspaceID int64, errorJSON []byte) (*DesktopTask, error)
Reconcile(ctx context.Context, desktopID uuid.UUID, workspaceID int64, status string, resultJSON, errorJSON []byte) (*DesktopTask, error)
MarkUnknownByClient(ctx context.Context, clientID uuid.UUID, workspaceID int64, errorJSON []byte) (int64, error)
CreateAttempt(ctx context.Context, params CreateDesktopTaskAttemptParams) (*DesktopTaskAttempt, error)
FinishAttempt(ctx context.Context, params FinishDesktopTaskAttemptParams) error
}
type desktopTaskRepository struct {
q generated.Querier
}
func NewDesktopTaskRepository(db generated.DBTX) DesktopTaskRepository {
return &desktopTaskRepository{q: newQuerier(db)}
}
func (r *desktopTaskRepository) CreatePublishJob(ctx context.Context, params CreateDesktopPublishJobParams) (*DesktopPublishJob, error) {
row, err := r.q.CreateDesktopPublishJob(ctx, generated.CreateDesktopPublishJobParams{
DesktopID: pgUUID(params.DesktopID),
TenantID: params.TenantID,
WorkspaceID: params.WorkspaceID,
CreatedByUserID: params.CreatedByUserID,
Title: params.Title,
ContentRef: params.ContentRef,
ScheduledAt: pgTimestamp(params.ScheduledAt),
})
if err != nil {
return nil, err
}
return desktopPublishJobFromGenerated(row), nil
}
func (r *desktopTaskRepository) CreateTask(ctx context.Context, params CreateDesktopTaskParams) (*DesktopTask, error) {
row, err := r.q.CreateDesktopTask(ctx, generated.CreateDesktopTaskParams{
DesktopID: pgUUID(params.DesktopID),
JobID: pgUUID(params.JobID),
TenantID: params.TenantID,
WorkspaceID: params.WorkspaceID,
TargetAccountID: pgUUID(params.TargetAccountID),
TargetClientID: pgUUID(params.TargetClientID),
PlatformID: params.Platform,
Kind: params.Kind,
Payload: params.Payload,
Status: params.Status,
DedupKey: pgText(params.DedupKey),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) GetByDesktopID(ctx context.Context, desktopID uuid.UUID, workspaceID int64) (*DesktopTask, error) {
row, err := r.q.GetDesktopTaskByDesktopID(ctx, generated.GetDesktopTaskByDesktopIDParams{
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) LeaseNextQueued(ctx context.Context, clientID uuid.UUID, kind *string, params DesktopTaskLeaseParams) (*DesktopTask, error) {
row, err := r.q.LeaseNextQueuedDesktopTask(ctx, generated.LeaseNextQueuedDesktopTaskParams{
AttemptID: pgUUID(params.AttemptID),
LeaseTokenHash: params.LeaseTokenHash,
ClientID: pgUUID(clientID),
Kind: pgText(kind),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) LeaseQueuedByDesktopID(ctx context.Context, desktopID, clientID uuid.UUID, params DesktopTaskLeaseParams) (*DesktopTask, error) {
row, err := r.q.LeaseQueuedDesktopTaskByDesktopID(ctx, generated.LeaseQueuedDesktopTaskByDesktopIDParams{
AttemptID: pgUUID(params.AttemptID),
LeaseTokenHash: params.LeaseTokenHash,
DesktopID: pgUUID(desktopID),
ClientID: pgUUID(clientID),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) ExtendLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte) (*DesktopTask, error) {
row, err := r.q.ExtendDesktopTaskLease(ctx, generated.ExtendDesktopTaskLeaseParams{
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) Complete(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, status string, resultJSON, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.CompleteDesktopTask(ctx, generated.CompleteDesktopTaskParams{
Status: status,
Result: resultJSON,
Error: errorJSON,
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) CancelByLease(ctx context.Context, desktopID uuid.UUID, leaseTokenHash []byte, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.CancelDesktopTaskByLease(ctx, generated.CancelDesktopTaskByLeaseParams{
Error: errorJSON,
DesktopID: pgUUID(desktopID),
LeaseTokenHash: leaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) CancelByClient(ctx context.Context, desktopID, clientID uuid.UUID, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.CancelDesktopTaskByClient(ctx, generated.CancelDesktopTaskByClientParams{
Error: errorJSON,
DesktopID: pgUUID(desktopID),
ClientID: pgUUID(clientID),
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) TenantCancel(ctx context.Context, desktopID uuid.UUID, workspaceID int64, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.TenantCancelDesktopTask(ctx, generated.TenantCancelDesktopTaskParams{
Error: errorJSON,
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) Reconcile(ctx context.Context, desktopID uuid.UUID, workspaceID int64, status string, resultJSON, errorJSON []byte) (*DesktopTask, error) {
row, err := r.q.ReconcileDesktopTask(ctx, generated.ReconcileDesktopTaskParams{
Status: status,
Result: resultJSON,
Error: errorJSON,
DesktopID: pgUUID(desktopID),
WorkspaceID: workspaceID,
})
if err != nil {
return nil, err
}
return desktopTaskFromGenerated(row), nil
}
func (r *desktopTaskRepository) MarkUnknownByClient(ctx context.Context, clientID uuid.UUID, workspaceID int64, errorJSON []byte) (int64, error) {
return r.q.MarkDesktopTasksUnknownByClient(ctx, generated.MarkDesktopTasksUnknownByClientParams{
Error: errorJSON,
ClientID: pgUUID(clientID),
WorkspaceID: workspaceID,
})
}
func (r *desktopTaskRepository) CreateAttempt(ctx context.Context, params CreateDesktopTaskAttemptParams) (*DesktopTaskAttempt, error) {
row, err := r.q.CreateDesktopTaskAttempt(ctx, generated.CreateDesktopTaskAttemptParams{
DesktopID: pgUUID(params.DesktopID),
TaskID: pgUUID(params.TaskID),
ClientID: pgUUID(params.ClientID),
LeaseTokenHash: params.LeaseTokenHash,
})
if err != nil {
return nil, err
}
return desktopTaskAttemptFromGenerated(row), nil
}
func (r *desktopTaskRepository) FinishAttempt(ctx context.Context, params FinishDesktopTaskAttemptParams) error {
return r.q.FinishDesktopTaskAttempt(ctx, generated.FinishDesktopTaskAttemptParams{
FinalStatus: pgText(params.FinalStatus),
Error: params.Error,
TaskID: pgUUID(params.TaskID),
AttemptID: pgUUID(params.AttemptID),
})
}
func desktopPublishJobFromGenerated(row generated.DesktopPublishJob) *DesktopPublishJob {
return &DesktopPublishJob{
DesktopID: uuidFromPG(row.DesktopID),
TenantID: row.TenantID,
WorkspaceID: row.WorkspaceID,
CreatedByUserID: row.CreatedByUserID,
Title: row.Title,
ContentRef: row.ContentRef,
ScheduledAt: optionalTime(row.ScheduledAt),
CreatedAt: timeFromTimestamp(row.CreatedAt),
UpdatedAt: timeFromTimestamp(row.UpdatedAt),
}
}
func desktopTaskFromGenerated(row generated.DesktopTask) *DesktopTask {
return &DesktopTask{
DesktopID: uuidFromPG(row.DesktopID),
JobID: uuidFromPG(row.JobID),
TenantID: row.TenantID,
WorkspaceID: row.WorkspaceID,
TargetAccountID: uuidFromPG(row.TargetAccountID),
TargetClientID: uuidFromPG(row.TargetClientID),
Platform: row.PlatformID,
Kind: row.Kind,
Payload: row.Payload,
Status: row.Status,
Priority: int(row.Priority),
Lane: row.Lane,
LaneWeight: int(row.LaneWeight),
Source: row.Source,
SchedulerGroupKey: nullableText(row.SchedulerGroupKey),
MonitorTaskID: nullableInt64(row.MonitorTaskID),
SupersedesTaskID: nullableUUID(row.SupersedesTaskID),
ControlFlags: row.ControlFlags,
InterruptGeneration: int(row.InterruptGeneration),
DedupKey: nullableText(row.DedupKey),
ActiveAttemptID: nullableUUID(row.ActiveAttemptID),
LeaseExpiresAt: optionalTime(row.LeaseExpiresAt),
Attempts: int(row.Attempts),
Result: row.Result,
Error: row.Error,
StartedAt: optionalTime(row.StartedAt),
InterruptedAt: optionalTime(row.InterruptedAt),
InterruptReason: nullableText(row.InterruptReason),
EnqueuedAt: timeFromTimestamp(row.EnqueuedAt),
CreatedAt: timeFromTimestamp(row.CreatedAt),
UpdatedAt: timeFromTimestamp(row.UpdatedAt),
}
}
func desktopTaskAttemptFromGenerated(row generated.DesktopTaskAttempt) *DesktopTaskAttempt {
return &DesktopTaskAttempt{
DesktopID: uuidFromPG(row.DesktopID),
TaskID: uuidFromPG(row.TaskID),
ClientID: uuidFromPG(row.ClientID),
StartedAt: timeFromTimestamp(row.StartedAt),
EndedAt: optionalTime(row.EndedAt),
FinalStatus: nullableText(row.FinalStatus),
Error: row.Error,
CreatedAt: timeFromTimestamp(row.CreatedAt),
}
}