package main import ( "encoding/json" "net/http" ) type HealthcheckShortResult struct { ResponseTime float64 `json:"response_time"` SuccessPercentage float64 `json:"success_percentage"` } func healthCheckHandler(w http.ResponseWriter, r *http.Request) { rows, err := db.Query(` SELECT h.public_name, r.success_percentage, r.response_time FROM hosts h JOIN results r ON h.id = r.host_id ORDER BY r.timestamp DESC, r.id DESC LIMIT 1000; `) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() results := make(map[string][]HealthcheckShortResult) for rows.Next() { var publicName string var successPercentage float64 var responseTime float64 err := rows.Scan(&publicName, &successPercentage, &responseTime) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if len(results[publicName]) >= 50 { continue } result := HealthcheckShortResult{ ResponseTime: responseTime, SuccessPercentage: successPercentage, } results[publicName] = append(results[publicName], result) } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(results) } func statusHandler(w http.ResponseWriter, r *http.Request) { statuses, err := getHostStatus() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(statuses) } type HostStatus map[string]string func getHostStatus() (map[string]string, error) { resultByHost := make(map[string][]float64) statuses := make(HostStatus) hosts, err := db.Query(`select id, public_name from hosts`) if err != nil { return nil, err } for hosts.Next() { var id int64 var publicName string err := hosts.Scan(&id, &publicName) if err != nil { return nil, err } results, err := db.Query(`select success_percentage from results where host_id = $1 order by timestamp desc, id desc limit 10`, id) if err != nil { return nil, err } for results.Next() { var successPercentage float64 results.Scan(&successPercentage) resultByHost[publicName] = append(resultByHost[publicName], successPercentage) } } for publicName, result := range resultByHost { total := 10 if len(result) < total { continue } var sum float64 = 0.0 var halfSum float64 = 0.0 for _, value := range result[len(result)-total:] { sum += value } for _, value := range result[len(result)-total/2:] { halfSum += value } average := sum / float64(total) recent := halfSum / float64(total/2) var status string if average > 0.95 { status = "healthy" } else if average > 0.6 { if recent < 0.5 { status = "unstable failing" } else if recent > 0.8 { status = "unstable recovering" } else { status = "unstable" } } else { if recent > 0.6 { status = "unhealthy recovering" } else { status = "unhealthy" } } statuses[publicName] = status } return statuses, nil }