ensure resource store is populated before WebSocket broadcasts
- Added PopulateFromSnapshot method to resources.Store - Extended ResourceStoreInterface to include PopulateFromSnapshot - Monitor now calls updateResourceStore before broadcasts - This ensures resources are fresh on every WebSocket broadcast Without this, the store would only be populated when /api/resources or /api/state endpoints are hit, leaving WebSocket broadcasts empty.
This commit is contained in:
parent
55f10ce36c
commit
881f00a5d9
2 changed files with 74 additions and 2 deletions
|
|
@ -93,6 +93,8 @@ type ResourceStoreInterface interface {
|
||||||
GetPollingRecommendations() map[string]float64
|
GetPollingRecommendations() map[string]float64
|
||||||
// GetAll returns all resources in the store (for WebSocket broadcasts)
|
// GetAll returns all resources in the store (for WebSocket broadcasts)
|
||||||
GetAll() []resources.Resource
|
GetAll() []resources.Resource
|
||||||
|
// PopulateFromSnapshot updates the store with data from a StateSnapshot
|
||||||
|
PopulateFromSnapshot(snapshot models.StateSnapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNodeDisplayName(instance *config.PVEInstance, nodeName string) string {
|
func getNodeDisplayName(instance *config.PVEInstance, nodeName string) string {
|
||||||
|
|
@ -3290,7 +3292,8 @@ func (m *Monitor) Start(ctx context.Context, wsHub *websocket.Hub) {
|
||||||
Msg("Broadcasting state update (ticker)")
|
Msg("Broadcasting state update (ticker)")
|
||||||
// Convert to frontend format before broadcasting (converts time.Time to int64, etc.)
|
// Convert to frontend format before broadcasting (converts time.Time to int64, etc.)
|
||||||
frontendState := state.ToFrontend()
|
frontendState := state.ToFrontend()
|
||||||
// Inject unified resources if resource store is available
|
// Update and inject unified resources if resource store is available
|
||||||
|
m.updateResourceStore(state)
|
||||||
frontendState.Resources = m.getResourcesForBroadcast()
|
frontendState.Resources = m.getResourcesForBroadcast()
|
||||||
wsHub.BroadcastState(frontendState)
|
wsHub.BroadcastState(frontendState)
|
||||||
|
|
||||||
|
|
@ -6901,7 +6904,9 @@ func (m *Monitor) SetMockMode(enable bool) {
|
||||||
m.mu.RUnlock()
|
m.mu.RUnlock()
|
||||||
|
|
||||||
if hub != nil {
|
if hub != nil {
|
||||||
frontendState := m.GetState().ToFrontend()
|
state := m.GetState()
|
||||||
|
frontendState := state.ToFrontend()
|
||||||
|
m.updateResourceStore(state)
|
||||||
frontendState.Resources = m.getResourcesForBroadcast()
|
frontendState.Resources = m.getResourcesForBroadcast()
|
||||||
hub.BroadcastState(frontendState)
|
hub.BroadcastState(frontendState)
|
||||||
}
|
}
|
||||||
|
|
@ -7057,6 +7062,20 @@ func (m *Monitor) shouldSkipNodeMetrics(nodeName string) bool {
|
||||||
return should
|
return should
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateResourceStore populates the resource store with data from the current state.
|
||||||
|
// This should be called before broadcasting to ensure fresh data.
|
||||||
|
func (m *Monitor) updateResourceStore(state models.StateSnapshot) {
|
||||||
|
m.mu.RLock()
|
||||||
|
store := m.resourceStore
|
||||||
|
m.mu.RUnlock()
|
||||||
|
|
||||||
|
if store == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
store.PopulateFromSnapshot(state)
|
||||||
|
}
|
||||||
|
|
||||||
// getResourcesForBroadcast retrieves all resources from the store and converts them to frontend format.
|
// getResourcesForBroadcast retrieves all resources from the store and converts them to frontend format.
|
||||||
// Returns nil if no resource store is configured.
|
// Returns nil if no resource store is configured.
|
||||||
func (m *Monitor) getResourcesForBroadcast() []models.ResourceFrontend {
|
func (m *Monitor) getResourcesForBroadcast() []models.ResourceFrontend {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Store maintains a unified collection of all resources with deduplication.
|
// Store maintains a unified collection of all resources with deduplication.
|
||||||
|
|
@ -1024,3 +1026,54 @@ type PlatformSummary struct {
|
||||||
Count int
|
Count int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PopulateFromSnapshot converts all resources from a StateSnapshot to the unified store.
|
||||||
|
// This should be called whenever the state is updated (e.g., before WebSocket broadcasts).
|
||||||
|
func (s *Store) PopulateFromSnapshot(snapshot models.StateSnapshot) {
|
||||||
|
// Convert nodes
|
||||||
|
for _, node := range snapshot.Nodes {
|
||||||
|
r := FromNode(node)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert VMs
|
||||||
|
for _, vm := range snapshot.VMs {
|
||||||
|
r := FromVM(vm)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert containers
|
||||||
|
for _, ct := range snapshot.Containers {
|
||||||
|
r := FromContainer(ct)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert hosts
|
||||||
|
for _, host := range snapshot.Hosts {
|
||||||
|
r := FromHost(host)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert docker hosts and their containers
|
||||||
|
for _, dh := range snapshot.DockerHosts {
|
||||||
|
r := FromDockerHost(dh)
|
||||||
|
s.Upsert(r)
|
||||||
|
|
||||||
|
// Convert containers within the docker host
|
||||||
|
for _, dc := range dh.Containers {
|
||||||
|
r := FromDockerContainer(dc, dh.ID, dh.Hostname)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert PBS instances
|
||||||
|
for _, pbs := range snapshot.PBSInstances {
|
||||||
|
r := FromPBSInstance(pbs)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert storage
|
||||||
|
for _, storage := range snapshot.Storage {
|
||||||
|
r := FromStorage(storage)
|
||||||
|
s.Upsert(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue