Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dbfc98552 |
@@ -1,9 +1,11 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -256,6 +258,14 @@ func HeicodeListAgents(c *gin.Context) {
|
|||||||
agentError(c, "DEPLOYMENT_CONFLICT", "failed to list agents")
|
agentError(c, "DEPLOYMENT_CONFLICT", "failed to list agents")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Refresh live status from AM for every non-terminal agent BEFORE returning,
|
||||||
|
// so the list (and the desktop client that polls it) reflects reality without
|
||||||
|
// needing the detail panel to be opened. Previously only the detail/status
|
||||||
|
// endpoints refreshed, so a freshly-deployed agent stayed "Pending" in the
|
||||||
|
// list forever. Bounded: per-user agent count is capped (≤8) and the refreshes
|
||||||
|
// run concurrently under a short deadline, so the list never hangs on a slow AM.
|
||||||
|
refreshAgentStatusBatch(c.Request.Context(), rows)
|
||||||
|
|
||||||
items := make([]gin.H, 0, len(rows))
|
items := make([]gin.H, 0, len(rows))
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
items = append(items, templateAgentResponse(row))
|
items = append(items, templateAgentResponse(row))
|
||||||
@@ -263,9 +273,31 @@ func HeicodeListAgents(c *gin.Context) {
|
|||||||
common.ApiSuccess(c, gin.H{"items": items, "total": len(items)})
|
common.ApiSuccess(c, gin.H{"items": items, "total": len(items)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refreshAgentStatusBatch concurrently refreshes the live status of every
|
||||||
|
// non-terminal agent in rows (best-effort) under a single bounded deadline.
|
||||||
|
// Each row is updated in place + persisted by refreshAgentStatus.
|
||||||
|
func refreshAgentStatusBatch(ctx context.Context, rows []model.AgentDeployment) {
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, 8*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := range rows {
|
||||||
|
row := &rows[i]
|
||||||
|
if strings.TrimSpace(row.RuntimeDeploymentID) == "" ||
|
||||||
|
strings.EqualFold(strings.TrimSpace(row.Status), "stopped") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wg.Add(1)
|
||||||
|
go func(r *model.AgentDeployment) {
|
||||||
|
defer wg.Done()
|
||||||
|
refreshAgentStatus(ctx, r)
|
||||||
|
}(row)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
// refreshAgentStatus best-effort pulls the live status from AM and persists it.
|
// refreshAgentStatus best-effort pulls the live status from AM and persists it.
|
||||||
// On any AM error it keeps the last-known status (never blocks the read).
|
// On any AM error it keeps the last-known status (never blocks the read).
|
||||||
func refreshAgentStatus(c *gin.Context, row *model.AgentDeployment) {
|
func refreshAgentStatus(ctx context.Context, row *model.AgentDeployment) {
|
||||||
if strings.TrimSpace(row.RuntimeDeploymentID) == "" {
|
if strings.TrimSpace(row.RuntimeDeploymentID) == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -275,7 +307,7 @@ func refreshAgentStatus(c *gin.Context, row *model.AgentDeployment) {
|
|||||||
if strings.EqualFold(strings.TrimSpace(row.Status), "stopped") {
|
if strings.EqualFold(strings.TrimSpace(row.Status), "stopped") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
status, err := amGetAgentStatus(c.Request.Context(), row.RuntimeDeploymentID)
|
status, err := amGetAgentStatus(ctx, row.RuntimeDeploymentID)
|
||||||
if err != nil || strings.TrimSpace(status) == "" || status == row.Status {
|
if err != nil || strings.TrimSpace(status) == "" || status == row.Status {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -299,7 +331,7 @@ func HeicodeGetAgent(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
refreshAgentStatus(c, &row)
|
refreshAgentStatus(c.Request.Context(), &row)
|
||||||
common.ApiSuccess(c, templateAgentResponse(row))
|
common.ApiSuccess(c, templateAgentResponse(row))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +342,7 @@ func HeicodeGetAgentStatus(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
refreshAgentStatus(c, &row)
|
refreshAgentStatus(c.Request.Context(), &row)
|
||||||
common.ApiSuccess(c, gin.H{
|
common.ApiSuccess(c, gin.H{
|
||||||
"agent_id": row.DeploymentID,
|
"agent_id": row.DeploymentID,
|
||||||
"status": row.Status,
|
"status": row.Status,
|
||||||
|
|||||||
Reference in New Issue
Block a user