Files
gatus/watchdog/watchdog.go
T

73 lines
2.4 KiB
Go
Raw Normal View History

2019-09-04 19:37:13 -04:00
package watchdog
import (
"context"
"time"
2020-10-30 21:00:03 +05:30
2022-12-06 01:41:09 -05:00
"github.com/TwiN/gatus/v5/config"
2025-09-05 15:39:12 -04:00
"golang.org/x/sync/semaphore"
)
const (
// UnlimitedConcurrencyWeight is the semaphore weight used when concurrency is set to 0 (unlimited).
// This provides a practical upper limit while allowing very high concurrency for large deployments.
UnlimitedConcurrencyWeight = 10000
)
var (
2025-09-05 15:39:12 -04:00
// monitoringSemaphore is used to limit the number of endpoints/suites that can be evaluated concurrently.
// Without this, conditions using response time may become inaccurate.
2025-09-05 15:39:12 -04:00
monitoringSemaphore *semaphore.Weighted
ctx context.Context
cancelFunc context.CancelFunc
)
2021-10-23 16:47:12 -04:00
// Monitor loops over each endpoint and starts a goroutine to monitor each endpoint separately
func Monitor(cfg *config.Config) {
ctx, cancelFunc = context.WithCancel(context.Background())
2025-09-05 15:39:12 -04:00
// Initialize semaphore based on concurrency configuration
if cfg.Concurrency == 0 {
// Unlimited concurrency - use a very high limit
monitoringSemaphore = semaphore.NewWeighted(UnlimitedConcurrencyWeight)
} else {
// Limited concurrency based on configuration
monitoringSemaphore = semaphore.NewWeighted(int64(cfg.Concurrency))
}
extraLabels := cfg.GetUniqueExtraMetricLabels()
2021-10-23 16:47:12 -04:00
for _, endpoint := range cfg.Endpoints {
if endpoint.IsEnabled() {
2021-09-22 00:04:51 -04:00
// To prevent multiple requests from running at the same time, we'll wait for a little before each iteration
2025-09-05 15:39:12 -04:00
time.Sleep(222 * time.Millisecond)
go monitorEndpoint(endpoint, cfg, extraLabels, ctx)
2021-09-19 00:52:11 +09:00
}
}
for _, externalEndpoint := range cfg.ExternalEndpoints {
// Check if the external endpoint is enabled and is using heartbeat
// If the external endpoint does not use heartbeat, then it does not need to be monitored periodically, because
// alerting is checked every time an external endpoint is pushed to Gatus, unlike normal endpoints.
if externalEndpoint.IsEnabled() && externalEndpoint.Heartbeat.Interval > 0 {
2025-09-05 15:39:12 -04:00
go monitorExternalEndpointHeartbeat(externalEndpoint, cfg, extraLabels, ctx)
}
}
2025-09-05 15:39:12 -04:00
for _, suite := range cfg.Suites {
if suite.IsEnabled() {
time.Sleep(222 * time.Millisecond)
go monitorSuite(suite, cfg, extraLabels, ctx)
}
}
2020-11-26 18:09:01 -05:00
}
2021-10-23 16:47:12 -04:00
// Shutdown stops monitoring all endpoints
func Shutdown(cfg *config.Config) {
2025-09-05 15:39:12 -04:00
// Stop in-flight HTTP connections
for _, ep := range cfg.Endpoints {
ep.Close()
}
2025-09-05 15:39:12 -04:00
for _, s := range cfg.Suites {
for _, ep := range s.Endpoints {
ep.Close()
}
}
cancelFunc()
}