mirror of
https://github.com/henrygd/beszel.git
synced 2026-04-21 04:01:50 +02:00
fix: address network probe code quality issues
- Use shared http.Client in ProbeManager to avoid connection/transport leak - Skip probe goroutine and agent request when system has no enabled probes - Validate HTTP probe target URL scheme (http:// or https://) on creation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,9 @@ import (
|
|||||||
|
|
||||||
// ProbeManager manages network probe tasks.
|
// ProbeManager manages network probe tasks.
|
||||||
type ProbeManager struct {
|
type ProbeManager struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
probes map[string]*probeTask // key = probe.Config.Key()
|
probes map[string]*probeTask // key = probe.Config.Key()
|
||||||
|
httpClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
type probeTask struct {
|
type probeTask struct {
|
||||||
@@ -33,6 +34,7 @@ type probeSample struct {
|
|||||||
func newProbeManager() *ProbeManager {
|
func newProbeManager() *ProbeManager {
|
||||||
return &ProbeManager{
|
return &ProbeManager{
|
||||||
probes: make(map[string]*probeTask),
|
probes: make(map[string]*probeTask),
|
||||||
|
httpClient: &http.Client{Timeout: 10 * time.Second},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +170,7 @@ func (pm *ProbeManager) executeProbe(task *probeTask) {
|
|||||||
case "tcp":
|
case "tcp":
|
||||||
latencyMs = probeTCP(task.config.Target, task.config.Port)
|
latencyMs = probeTCP(task.config.Target, task.config.Port)
|
||||||
case "http":
|
case "http":
|
||||||
latencyMs = probeHTTP(task.config.Target)
|
latencyMs = probeHTTP(pm.httpClient, task.config.Target)
|
||||||
default:
|
default:
|
||||||
slog.Warn("unknown probe protocol", "protocol", task.config.Protocol)
|
slog.Warn("unknown probe protocol", "protocol", task.config.Protocol)
|
||||||
return
|
return
|
||||||
@@ -212,8 +214,7 @@ func probeTCP(target string, port uint16) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// probeHTTP measures HTTP GET request latency. Returns -1 on failure.
|
// probeHTTP measures HTTP GET request latency. Returns -1 on failure.
|
||||||
func probeHTTP(url string) float64 {
|
func probeHTTP(client *http.Client, url string) float64 {
|
||||||
client := &http.Client{Timeout: 10 * time.Second}
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
resp, err := client.Get(url)
|
resp, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package hub
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
@@ -75,6 +76,9 @@ func (h *Hub) createNetworkProbe(e *core.RequestEvent) error {
|
|||||||
if req.Protocol != "icmp" && req.Protocol != "tcp" && req.Protocol != "http" {
|
if req.Protocol != "icmp" && req.Protocol != "tcp" && req.Protocol != "http" {
|
||||||
return e.BadRequestError("protocol must be icmp, tcp, or http", nil)
|
return e.BadRequestError("protocol must be icmp, tcp, or http", nil)
|
||||||
}
|
}
|
||||||
|
if req.Protocol == "http" && !strings.HasPrefix(req.Target, "http://") && !strings.HasPrefix(req.Target, "https://") {
|
||||||
|
return e.BadRequestError("http probe target must start with http:// or https://", nil)
|
||||||
|
}
|
||||||
if req.Interval <= 0 {
|
if req.Interval <= 0 {
|
||||||
req.Interval = 10
|
req.Interval = 10
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,9 @@ func (sys *System) update() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch and save network probe results
|
// Fetch and save network probe results
|
||||||
go sys.fetchAndSaveProbeResults()
|
if sys.hasEnabledProbes() {
|
||||||
|
go sys.fetchAndSaveProbeResults()
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,17 +27,17 @@ func (sys *System) FetchNetworkProbeResults() (map[string]probe.Result, error) {
|
|||||||
return results, err
|
return results, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasEnabledProbes returns true if this system has any enabled network probes.
|
||||||
|
func (sys *System) hasEnabledProbes() bool {
|
||||||
|
count, err := sys.manager.hub.CountRecords("network_probes",
|
||||||
|
dbx.NewExp("system = {:system} AND enabled = true", dbx.Params{"system": sys.Id}))
|
||||||
|
return err == nil && count > 0
|
||||||
|
}
|
||||||
|
|
||||||
// fetchAndSaveProbeResults fetches probe results and saves them to the database.
|
// fetchAndSaveProbeResults fetches probe results and saves them to the database.
|
||||||
func (sys *System) fetchAndSaveProbeResults() {
|
func (sys *System) fetchAndSaveProbeResults() {
|
||||||
hub := sys.manager.hub
|
hub := sys.manager.hub
|
||||||
|
|
||||||
// Check if this system has any probes
|
|
||||||
count, err := hub.CountRecords("network_probes",
|
|
||||||
dbx.NewExp("system = {:system} AND enabled = true", dbx.Params{"system": sys.Id}))
|
|
||||||
if err != nil || count == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
results, err := sys.FetchNetworkProbeResults()
|
results, err := sys.FetchNetworkProbeResults()
|
||||||
if err != nil || len(results) == 0 {
|
if err != nil || len(results) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -168,8 +168,10 @@ func (sm *SystemManager) fetchRealtimeDataAndNotify() {
|
|||||||
Containers: data.Containers,
|
Containers: data.Containers,
|
||||||
}
|
}
|
||||||
// Fetch network probe results (lightweight in-memory read on agent)
|
// Fetch network probe results (lightweight in-memory read on agent)
|
||||||
if probes, err := sys.FetchNetworkProbeResults(); err == nil && len(probes) > 0 {
|
if sys.hasEnabledProbes() {
|
||||||
payload.Probes = probes
|
if probes, err := sys.FetchNetworkProbeResults(); err == nil && len(probes) > 0 {
|
||||||
|
payload.Probes = probes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bytes, err := json.Marshal(payload)
|
bytes, err := json.Marshal(payload)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user