change to atomic.bool for fetching details / smart

This commit is contained in:
henrygd
2025-12-18 15:02:59 -05:00
parent 8627e3ee97
commit 330d375997

View File

@@ -9,7 +9,7 @@ import (
"math/rand"
"net"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/henrygd/beszel/internal/common"
@@ -29,20 +29,21 @@ import (
)
type System struct {
Id string `db:"id"`
Host string `db:"host"`
Port string `db:"port"`
Status string `db:"status"`
manager *SystemManager // Manager that this system belongs to
client *ssh.Client // SSH client for fetching data
data *system.CombinedData // system data from agent
ctx context.Context // Context for stopping the updater
cancel context.CancelFunc // Stops and removes system from updater
WsConn *ws.WsConn // Handler for agent WebSocket connection
agentVersion semver.Version // Agent version
updateTicker *time.Ticker // Ticker for updating the system
smartOnce sync.Once // Once for fetching and saving smart devices
detailsOnce sync.Once // Once for fetching and saving static system details
Id string `db:"id"`
Host string `db:"host"`
Port string `db:"port"`
Status string `db:"status"`
manager *SystemManager // Manager that this system belongs to
client *ssh.Client // SSH client for fetching data
data *system.CombinedData // system data from agent
ctx context.Context // Context for stopping the updater
cancel context.CancelFunc // Stops and removes system from updater
WsConn *ws.WsConn // Handler for agent WebSocket connection
agentVersion semver.Version // Agent version
updateTicker *time.Ticker // Ticker for updating the system
detailsFetched atomic.Bool // True if static system details have been fetched and saved
smartFetched atomic.Bool // True if SMART devices have been fetched and saved
smartFetching atomic.Bool // True if SMART devices are currently being fetched
}
func (sm *SystemManager) NewSystem(systemId string) *System {
@@ -118,10 +119,10 @@ func (sys *System) update() error {
options := common.DataRequestOptions{
CacheTimeMs: uint16(interval),
}
// fetch system details only on the first update
sys.detailsOnce.Do(func() {
// fetch system details if not already fetched
if !sys.detailsFetched.Load() {
options.IncludeDetails = true
})
}
data, err := sys.fetchDataFromAgent(options)
if err == nil {
_, err = sys.createRecords(data)
@@ -150,17 +151,11 @@ func (sys *System) createRecords(data *system.CombinedData) (*core.Record, error
}
hub := sys.manager.hub
err = hub.RunInTransaction(func(txApp core.App) error {
if data.Details != nil {
if err := createSystemDetailsRecord(txApp, data.Details, sys.Id); err != nil {
return err
}
}
// add system_stats and container_stats records
// add system_stats record
systemStatsCollection, err := txApp.FindCachedCollectionByNameOrId("system_stats")
if err != nil {
return err
}
systemStatsRecord := core.NewRecord(systemStatsCollection)
systemStatsRecord.Set("system", systemRecord.Id)
systemStatsRecord.Set("stats", data.Stats)
@@ -168,14 +163,14 @@ func (sys *System) createRecords(data *system.CombinedData) (*core.Record, error
if err := txApp.SaveNoValidate(systemStatsRecord); err != nil {
return err
}
// add containers and container_stats records
if len(data.Containers) > 0 {
// add / update containers records
if data.Containers[0].Id != "" {
if err := createContainerRecords(txApp, data.Containers, sys.Id); err != nil {
return err
}
}
// add new container_stats record
containerStatsCollection, err := txApp.FindCachedCollectionByNameOrId("container_stats")
if err != nil {
return err
@@ -196,9 +191,16 @@ func (sys *System) createRecords(data *system.CombinedData) (*core.Record, error
}
}
// add system details record
if data.Details != nil {
if err := createSystemDetailsRecord(txApp, data.Details, sys.Id); err != nil {
return err
}
sys.detailsFetched.Store(true)
}
// update system record (do this last because it triggers alerts and we need above records to be inserted first)
systemRecord.Set("status", up)
systemRecord.Set("info", data.Info)
if err := txApp.SaveNoValidate(systemRecord); err != nil {
return err
@@ -208,15 +210,21 @@ func (sys *System) createRecords(data *system.CombinedData) (*core.Record, error
// Fetch and save SMART devices when system first comes online
if err == nil {
sys.smartOnce.Do(func() {
go sys.FetchAndSaveSmartDevices()
})
if !sys.smartFetched.Load() && sys.smartFetching.CompareAndSwap(false, true) {
go func() {
defer sys.smartFetching.Store(false)
if err := sys.FetchAndSaveSmartDevices(); err == nil {
sys.smartFetched.Store(true)
}
}()
}
}
return systemRecord, err
}
func createSystemDetailsRecord(app core.App, data *system.Details, systemId string) error {
collectionName := "system_details"
params := dbx.Params{
"id": systemId,
"system": systemId,
@@ -232,12 +240,11 @@ func createSystemDetailsRecord(app core.App, data *system.Details, systemId stri
"podman": data.Podman,
"updated": time.Now().UTC(),
}
queryString := `INSERT INTO system_details (id, system, hostname, kernel, cores, threads, cpu, os, os_name, arch, memory, podman, updated)
VALUES ({:id}, {:system}, {:hostname}, {:kernel}, {:cores}, {:threads}, {:cpu}, {:os}, {:os_name}, {:arch}, {:memory}, {:podman}, {:updated})
ON CONFLICT(id) DO UPDATE SET system = excluded.system, hostname = excluded.hostname, kernel = excluded.kernel, cores = excluded.cores,
threads = excluded.threads, cpu = excluded.cpu, os = excluded.os, os_name = excluded.os_name, arch = excluded.arch,
memory = excluded.memory, podman = excluded.podman, updated = excluded.updated`
_, err := app.DB().NewQuery(queryString).Bind(params).Execute()
result, err := app.DB().Update(collectionName, params, dbx.HashExp{"id": systemId}).Execute()
rowsAffected, _ := result.RowsAffected()
if err != nil || rowsAffected == 0 {
_, err = app.DB().Insert(collectionName, params).Execute()
}
return err
}