feat(nodes): live CPU/RAM/disk monitoring in the node list
Build backend images / build content-svc (push) Failing after 45s
Build backend images / build file-svc (push) Failing after 55s
Build backend images / build gateway (push) Failing after 53s
Build backend images / build identity-svc (push) Failing after 54s
Build backend images / build notification-svc (push) Failing after 53s
Build backend images / build render-svc (push) Failing after 47s
Build backend images / build studio-svc (push) Failing after 51s

- node-agent: internal/metrics — read CPU% (GetSystemTimes), RAM (GlobalMemoryStatusEx),
  disk used%/total (GetDiskFreeSpaceEx) via stdlib kernel32 (no external dep; windows
  build + non-windows stub). Heartbeat now reports cpu_pct/ram_available_mb/disk_used_pct/
  disk_total_gb + ae_running.
- render-svc: heartbeat persists last_disk_pct + disk_total_gb (migration 29); RenderNode
  model + node SELECT/scan carry them.
- admin: rewrite NodesTable to the real RenderNode shape (fixes a pre-existing items/V2Node
  mismatch that left the list empty) + a CPU/RAM/disk bars column + stale-heartbeat flag.
- assets-bundle ingestion: ProjectMediaBundle (jszip) auto-maps project.zip → project/scene
  image/demo/colour + music; PatchProject gains image/full_demo/shared_colors_svg.
- scan: RGBA (4-number) colours recognised + frshare single-int controls detected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-04 20:01:18 +03:30
parent 6661f53734
commit 0a7dd9b84c
18 changed files with 651 additions and 2834 deletions
+11 -8
View File
@@ -64,8 +64,8 @@ func (s *Store) GetNodeByID(ctx context.Context, id uuid.UUID) (*models.RenderNo
lifetime_task_count, lifetime_crash_count, consecutive_failures,
priority, is_active, accepts_new_jobs,
last_maintenance_at, next_maintenance_at, maintenance_reason,
cached_template_md5s, cache_used_gb, created_at, updated_at
FROM render.render_nodes WHERE id = $1`, id)
cached_template_md5s, cache_used_gb, created_at, updated_at, last_disk_pct, disk_total_gb
FROM render.render_nodes WHERE id = $1`, id)
if err != nil {
return nil, err
}
@@ -158,13 +158,15 @@ func (s *Store) UpdateNodeHeartbeat(ctx context.Context, nodeID uuid.UUID, req *
last_heartbeat_at = NOW(),
last_cpu_pct = $2,
last_ram_available_mb = $3,
ae_running = COALESCE($4, ae_running),
current_job_id = $5,
current_frame_job_id = $6,
last_disk_pct = $4,
disk_total_gb = COALESCE($5, disk_total_gb),
ae_running = COALESCE($6, ae_running),
current_job_id = $7,
current_frame_job_id = $8,
updated_at = NOW()
WHERE id = $7`,
req.Status, req.CPUPct, req.RAMAvailableMB, req.AERunning,
req.CurrentJobID, nil, nodeID,
WHERE id = $9`,
req.Status, req.CPUPct, req.RAMAvailableMB, req.DiskUsedPct, req.DiskTotalGB,
req.AERunning, req.CurrentJobID, nil, nodeID,
)
return err
}
@@ -846,6 +848,7 @@ func scanNodes(rows pgx.Rows) ([]*models.RenderNode, error) {
&n.Priority, &n.IsActive, &n.AcceptsNewJobs,
&n.LastMaintenanceAt, &n.NextMaintenanceAt, &n.MaintenanceReason,
&n.CachedTemplateMD5s, &n.CacheUsedGB, &n.CreatedAt, &n.UpdatedAt,
&n.LastDiskPct, &n.DiskTotalGB,
); err != nil {
return nil, err
}
@@ -112,6 +112,8 @@ type RenderNode struct {
LastHeartbeatAt *time.Time `json:"last_heartbeat_at,omitempty"`
LastCPUPct *int `json:"last_cpu_pct,omitempty"`
LastRAMAvailableMB *int `json:"last_ram_available_mb,omitempty"`
LastDiskPct *int `json:"last_disk_pct,omitempty"`
DiskTotalGB *int `json:"disk_total_gb,omitempty"`
AERunning bool `json:"ae_running"`
LifetimeTaskCount int64 `json:"lifetime_task_count"`
LifetimeCrashCount int `json:"lifetime_crash_count"`
@@ -369,6 +371,8 @@ type NodeHeartbeatRequest struct {
Status string `json:"status"`
CPUPct *int `json:"cpu_pct"`
RAMAvailableMB *int `json:"ram_available_mb"`
DiskUsedPct *int `json:"disk_used_pct"`
DiskTotalGB *int `json:"disk_total_gb"`
AERunning *bool `json:"ae_running"`
CurrentJobID *uuid.UUID `json:"current_job_id"`
CurrentFrame *int `json:"current_frame"`