Files
geo/server/internal/tenant/transport/desktop_task_handler.go
T
root 7605890a14 refactor(server/monitoring): route monitor desktop tasks by account presence
Daily monitoring tasks were pinned to a single primary client. If that
client went offline the task wedged even when another desktop client of
the same workspace was online and bound to the same account. Drop the
primary-client constraint on the materialized collect rows, and instead
pick a target per-platform from live account/client presence in Redis,
falling back to the DB client_id when the desktop client is still flagged
online. Desktop task lease for kind=monitor now matches by account
ownership in addition to target_client_id, so any client owning the
account can drain the queue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 09:14:24 +08:00

221 lines
5.9 KiB
Go

package transport
import (
"errors"
"io"
"strconv"
"strings"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/geo-platform/tenant-api/internal/bootstrap"
"github.com/geo-platform/tenant-api/internal/shared/auth"
"github.com/geo-platform/tenant-api/internal/shared/response"
"github.com/geo-platform/tenant-api/internal/tenant/app"
)
type DesktopTaskHandler struct {
svc *app.DesktopTaskService
publishSvc *app.PublishJobService
}
func NewDesktopTaskHandler(a *bootstrap.App) *DesktopTaskHandler {
return &DesktopTaskHandler{
svc: app.NewDesktopTaskService(
a.DB,
a.MonitoringDB,
a.RabbitMQ,
a.Logger,
).WithCache(a.Cache).WithRedis(a.Redis),
publishSvc: app.NewPublishJobService(
a.DB,
a.RabbitMQ,
a.Redis,
a.Logger,
).WithCache(a.Cache),
}
}
func (h *DesktopTaskHandler) Lease(c *gin.Context) {
var req app.LeaseDesktopTaskRequest
if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
var routeTaskID *uuid.UUID
if rawID := c.Param("id"); rawID != "" {
parsed, err := uuid.Parse(rawID)
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
routeTaskID = &parsed
}
data, err := h.svc.Lease(c.Request.Context(), MustDesktopClient(c.Request.Context()), req, routeTaskID)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) ListPublish(c *gin.Context) {
req := app.ListPublishTasksRequest{
Page: 1,
PageSize: 10,
Title: strings.TrimSpace(c.Query("title")),
}
if rawPage := c.Query("page"); rawPage != "" {
parsed, err := strconv.Atoi(rawPage)
if err != nil || parsed <= 0 {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", "page must be a positive integer"))
return
}
req.Page = parsed
}
rawPageSize := c.Query("page_size")
if rawPageSize == "" {
rawPageSize = c.Query("limit")
}
if rawPageSize != "" {
parsed, err := strconv.Atoi(rawPageSize)
if err != nil || parsed <= 0 {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", "page_size must be a positive integer"))
return
}
req.PageSize = parsed
}
data, err := h.svc.ListPublishTasks(c.Request.Context(), MustDesktopClient(c.Request.Context()), req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) Extend(c *gin.Context) {
desktopID, err := uuid.Parse(c.Param("id"))
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
var req app.ExtendDesktopTaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
data, err := h.svc.Extend(c.Request.Context(), MustDesktopClient(c.Request.Context()), desktopID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) Result(c *gin.Context) {
desktopID, err := uuid.Parse(c.Param("id"))
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
var req app.CompleteDesktopTaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
data, err := h.svc.Complete(c.Request.Context(), MustDesktopClient(c.Request.Context()), desktopID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) RetryPublish(c *gin.Context) {
desktopID, err := uuid.Parse(c.Param("id"))
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
data, err := h.publishSvc.RetryByDesktopTask(c.Request.Context(), MustDesktopClient(c.Request.Context()), desktopID)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) Cancel(c *gin.Context) {
desktopID, err := uuid.Parse(c.Param("id"))
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
var req app.CancelDesktopTaskRequest
if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
data, err := h.svc.Cancel(c.Request.Context(), MustDesktopClient(c.Request.Context()), desktopID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) TenantCancel(c *gin.Context) {
desktopID, err := uuid.Parse(c.Param("id"))
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
var req app.CancelDesktopTaskRequest
if err := c.ShouldBindJSON(&req); err != nil && !errors.Is(err, io.EOF) {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
data, err := h.svc.TenantCancel(c.Request.Context(), auth.MustActor(c.Request.Context()), desktopID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}
func (h *DesktopTaskHandler) Reconcile(c *gin.Context) {
desktopID, err := uuid.Parse(c.Param("id"))
if err != nil {
response.Error(c, response.ErrBadRequest(40084, "invalid_desktop_task_id", "task id must be a uuid"))
return
}
var req app.ReconcileDesktopTaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, response.ErrBadRequest(40001, "invalid_params", err.Error()))
return
}
data, err := h.svc.Reconcile(c.Request.Context(), auth.MustActor(c.Request.Context()), desktopID, req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, data)
}