gohttp/healthcheck/healthcheck.go

67 lines
1.6 KiB
Go
Raw Permalink Normal View History

package healthcheck
import (
"fmt"
"net/http"
"time"
"git.pyer.club/kingecg/gologger"
)
// HealthChecker 健康检查器
type HealthChecker struct {
client *http.Client
interval time.Duration
timeout time.Duration
retries int
}
func NewHealthChecker(interval time.Duration, timeout time.Duration, retries int) *HealthChecker {
return &HealthChecker{
client: &http.Client{
Timeout: timeout,
},
interval: interval,
timeout: timeout,
retries: retries,
}
}
// CheckHealth 检查上游服务器健康状态
func (hc *HealthChecker) CheckHealth(url string) bool {
logger := gologger.GetLogger("healthcheck")
for i := 0; i < hc.retries; i++ {
resp, err := hc.client.Get(url + "/health")
if err == nil && resp.StatusCode == http.StatusOK {
return true
}
logger.Warn(fmt.Sprintf("Health check failed for %s: %v", url, err))
time.Sleep(hc.timeout)
}
logger.Error(fmt.Sprintf("All health checks failed for %s", url))
return false
}
// StartHealthCheck 启动健康检查协程
func (hc *HealthChecker) StartHealthCheck(upstreams []string, onStatusChange func(string, bool)) {
logger := gologger.GetLogger("healthcheck")
go func() {
statusMap := make(map[string]bool)
for {
for _, upstream := range upstreams {
healthy := hc.CheckHealth(upstream)
if status, exists := statusMap[upstream]; exists {
if status != healthy {
logger.Info(fmt.Sprintf("Upstream %s status changed to %v", upstream, healthy))
if onStatusChange != nil {
onStatusChange(upstream, healthy)
}
}
}
statusMap[upstream] = healthy
}
time.Sleep(hc.interval)
}
}()
}