4142c53fa6
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>
377 lines
13 KiB
Go
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),
|
|
}
|
|
}
|