89 lines
1.9 KiB
Go
89 lines
1.9 KiB
Go
// Package checker periodically HTTP-checks services and updates status.json.
|
|
package checker
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"ridgwaysystems.org/website/internal/status"
|
|
)
|
|
|
|
// Start launches the background checker. It checks services every interval
|
|
// and updates status.json in dataDir. Services without a CheckURL are skipped.
|
|
func Start(dataDir string, interval time.Duration) {
|
|
go run(dataDir, interval)
|
|
}
|
|
|
|
func run(dataDir string, interval time.Duration) {
|
|
client := &http.Client{
|
|
Timeout: 10 * time.Second,
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
if len(via) >= 3 {
|
|
return http.ErrUseLastResponse
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
path := filepath.Join(dataDir, "status.json")
|
|
|
|
for {
|
|
check(client, path)
|
|
time.Sleep(interval)
|
|
}
|
|
}
|
|
|
|
func check(client *http.Client, path string) {
|
|
page, err := status.Load(path)
|
|
if err != nil {
|
|
log.Printf("checker: load %s: %v", path, err)
|
|
return
|
|
}
|
|
|
|
changed := false
|
|
for i, svc := range page.Services {
|
|
if svc.CheckURL == "" {
|
|
continue
|
|
}
|
|
|
|
prev := svc.Status
|
|
newStatus := probe(client, svc.CheckURL)
|
|
if newStatus != prev {
|
|
log.Printf("checker: %s %s → %s", svc.Name, prev, newStatus)
|
|
page.Services[i].Status = newStatus
|
|
changed = true
|
|
}
|
|
}
|
|
|
|
if changed {
|
|
if err := status.Save(path, page); err != nil {
|
|
log.Printf("checker: save %s: %v", path, err)
|
|
}
|
|
} else {
|
|
// Still update last_checked timestamp so the status page shows freshness
|
|
page.LastChecked = time.Now().UTC()
|
|
if err := status.Save(path, page); err != nil {
|
|
log.Printf("checker: save %s: %v", path, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func probe(client *http.Client, url string) string {
|
|
resp, err := client.Get(url)
|
|
if err != nil {
|
|
return "down"
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
switch {
|
|
case resp.StatusCode < 400:
|
|
return "up"
|
|
case resp.StatusCode >= 500:
|
|
return "down"
|
|
default:
|
|
// 4xx could mean the service is up but the URL is wrong; treat as degraded
|
|
return "degraded"
|
|
}
|
|
}
|