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>
136 lines
3.5 KiB
Go
136 lines
3.5 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/geo-platform/tenant-api/internal/shared/config"
|
|
"github.com/geo-platform/tenant-api/internal/shared/messaging/rabbitmq"
|
|
"github.com/geo-platform/tenant-api/internal/shared/stream"
|
|
)
|
|
|
|
func publishDesktopDispatchEvent(
|
|
ctx context.Context,
|
|
client *rabbitmq.Client,
|
|
logger *zap.Logger,
|
|
event stream.DesktopDispatchEvent,
|
|
) error {
|
|
if client == nil || strings.TrimSpace(event.TargetClientID) == "" {
|
|
return nil
|
|
}
|
|
|
|
routingKey := desktopDispatchRoutingKey(client.Config(), event.Kind, event.Lane, event.TargetClientID)
|
|
body, err := json.Marshal(event)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := client.PublishDesktopDispatch(ctx, routingKey, body); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func desktopDispatchRoutingKey(cfg config.RabbitMQConfig, kind, lane, targetClientID string) string {
|
|
prefix := strings.TrimSpace(cfg.DesktopDispatchPublishPrefix)
|
|
if strings.TrimSpace(kind) == "monitor" {
|
|
prefix = strings.TrimSpace(cfg.DesktopDispatchMonitorPrefix)
|
|
}
|
|
if prefix == "" {
|
|
if strings.TrimSpace(kind) == "monitor" {
|
|
prefix = "monitor"
|
|
} else {
|
|
prefix = "publish"
|
|
}
|
|
}
|
|
|
|
if strings.TrimSpace(kind) == "monitor" && strings.TrimSpace(lane) != "" {
|
|
return fmt.Sprintf("%s.%s.%s", prefix, monitorDispatchLaneSegment(lane), targetClientID)
|
|
}
|
|
if strings.TrimSpace(kind) == "monitor" {
|
|
return fmt.Sprintf("%s.normal.%s", prefix, targetClientID)
|
|
}
|
|
return fmt.Sprintf("%s.%s", prefix, targetClientID)
|
|
}
|
|
|
|
func monitorDispatchLaneSegment(lane string) string {
|
|
switch strings.TrimSpace(lane) {
|
|
case "high":
|
|
return "high"
|
|
case "retry":
|
|
return "retry"
|
|
default:
|
|
return "normal"
|
|
}
|
|
}
|
|
|
|
func publishMonitorDispatchSignal(
|
|
ctx context.Context,
|
|
client *rabbitmq.Client,
|
|
logger *zap.Logger,
|
|
workspaceID int64,
|
|
targetClientID string,
|
|
lane string,
|
|
priority int,
|
|
interruptGeneration int,
|
|
) {
|
|
event := stream.DesktopDispatchEvent{
|
|
Type: "task_available",
|
|
TaskID: "",
|
|
JobID: "",
|
|
WorkspaceID: workspaceID,
|
|
TargetClientID: targetClientID,
|
|
Status: "queued",
|
|
Kind: "monitor",
|
|
Priority: priority,
|
|
Lane: strings.TrimSpace(lane),
|
|
InterruptGeneration: interruptGeneration,
|
|
SignalOnly: true,
|
|
UpdatedAt: time.Now().UTC(),
|
|
}
|
|
if err := publishDesktopDispatchEvent(ctx, client, logger, event); err != nil && logger != nil {
|
|
logger.Warn("monitor dispatch signal publish failed",
|
|
zap.String("target_client_id", targetClientID),
|
|
zap.String("lane", lane),
|
|
zap.Error(err),
|
|
)
|
|
}
|
|
}
|
|
|
|
func publishMonitorControlEvent(
|
|
ctx context.Context,
|
|
client *rabbitmq.Client,
|
|
logger *zap.Logger,
|
|
workspaceID int64,
|
|
targetClientID string,
|
|
taskID int64,
|
|
reason string,
|
|
interruptGeneration int,
|
|
) {
|
|
event := stream.DesktopDispatchEvent{
|
|
Type: "task_control",
|
|
TaskID: fmt.Sprintf("%d", taskID),
|
|
JobID: "",
|
|
WorkspaceID: workspaceID,
|
|
TargetClientID: targetClientID,
|
|
Status: "queued",
|
|
Kind: "monitor",
|
|
Lane: "high",
|
|
InterruptGeneration: interruptGeneration,
|
|
Control: "interrupt_requested",
|
|
Reason: reason,
|
|
UpdatedAt: time.Now().UTC(),
|
|
}
|
|
if err := publishDesktopDispatchEvent(ctx, client, logger, event); err != nil && logger != nil {
|
|
logger.Warn("monitor control event publish failed",
|
|
zap.String("target_client_id", targetClientID),
|
|
zap.Int64("task_id", taskID),
|
|
zap.Error(err),
|
|
)
|
|
}
|
|
}
|