package proxy import ( "io" "io/ioutil" "net/http" "time" ) type StaticUpstream struct { From string Hosts HostPool Policy Policy FailTimeout time.Duration MaxFails int32 HealthCheck struct { Path string Interval time.Duration } } func (u *StaticUpstream) from() string { return u.From } func (u *StaticUpstream) healthCheck() { for _, host := range u.Hosts { hostUrl := host.Name + u.HealthCheck.Path if r, err := http.Get(hostUrl); err == nil { io.Copy(ioutil.Discard, r.Body) r.Body.Close() host.Unhealthy = r.StatusCode < 200 || r.StatusCode >= 400 } else { host.Unhealthy = true } } } func (u *StaticUpstream) HealthCheckWorker(stop chan struct{}) { ticker := time.NewTicker(u.HealthCheck.Interval) u.healthCheck() for { select { case <-ticker.C: u.healthCheck() case <-stop: // TODO: the library should provide a stop channel and global // waitgroup to allow goroutines started by plugins a chance // to clean themselves up. } } } func (u *StaticUpstream) Select() *UpstreamHost { pool := u.Hosts if len(pool) == 1 { if pool[0].Down() { return nil } return pool[0] } allDown := true for _, host := range pool { if !host.Down() { allDown = false break } } if allDown { return nil } if u.Policy == nil { return (&Random{}).Select(pool) } else { return u.Policy.Select(pool) } }