|
@@ -1,39 +1,71 @@
|
|
|
package loadbalance
|
|
|
|
|
|
import (
|
|
|
- "net/http"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
-// Return the last ping status to see if the target is online
|
|
|
-func (m *RouteManager) IsTargetOnline(matchingDomainOrIp string) bool {
|
|
|
- value, ok := m.LoadBalanceMap.Load(matchingDomainOrIp)
|
|
|
+// Return if the target host is online
|
|
|
+func (m *RouteManager) IsTargetOnline(upstreamIP string) bool {
|
|
|
+ value, ok := m.OnlineStatus.Load(upstreamIP)
|
|
|
if !ok {
|
|
|
- return false
|
|
|
+ // Assume online if not found, also update the map
|
|
|
+ m.OnlineStatus.Store(upstreamIP, true)
|
|
|
+ return true
|
|
|
}
|
|
|
|
|
|
isOnline, ok := value.(bool)
|
|
|
return ok && isOnline
|
|
|
}
|
|
|
|
|
|
-// Ping a target to see if it is online
|
|
|
-func PingTarget(targetMatchingDomainOrIp string, requireTLS bool) bool {
|
|
|
- client := &http.Client{
|
|
|
- Timeout: 10 * time.Second,
|
|
|
+// Notify the host online state, should be called from uptime monitor
|
|
|
+func (m *RouteManager) NotifyHostOnlineState(upstreamIP string, isOnline bool) {
|
|
|
+ //if the upstream IP contains http or https, strip it
|
|
|
+ upstreamIP = strings.TrimPrefix(upstreamIP, "http://")
|
|
|
+ upstreamIP = strings.TrimPrefix(upstreamIP, "https://")
|
|
|
+
|
|
|
+ //Check previous state and update
|
|
|
+ if m.IsTargetOnline(upstreamIP) == isOnline {
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- url := targetMatchingDomainOrIp
|
|
|
- if requireTLS {
|
|
|
- url = "https://" + url
|
|
|
- } else {
|
|
|
- url = "http://" + url
|
|
|
+ m.OnlineStatus.Store(upstreamIP, isOnline)
|
|
|
+ m.println("Updating upstream "+upstreamIP+" online state to "+strconv.FormatBool(isOnline), nil)
|
|
|
+}
|
|
|
+
|
|
|
+// Set this host unreachable for a given amount of time defined in timeout
|
|
|
+// this shall be used in passive fallback. The uptime monitor should call to NotifyHostOnlineState() instead
|
|
|
+func (m *RouteManager) NotifyHostUnreachableWithTimeout(upstreamIp string, timeout int64) {
|
|
|
+ //if the upstream IP contains http or https, strip it
|
|
|
+ upstreamIp = strings.TrimPrefix(upstreamIp, "http://")
|
|
|
+ upstreamIp = strings.TrimPrefix(upstreamIp, "https://")
|
|
|
+ if timeout <= 0 {
|
|
|
+ //Set to the default timeout
|
|
|
+ timeout = 60
|
|
|
}
|
|
|
|
|
|
- resp, err := client.Get(url)
|
|
|
- if err != nil {
|
|
|
- return false
|
|
|
+ if !m.IsTargetOnline(upstreamIp) {
|
|
|
+ //Already offline
|
|
|
+ return
|
|
|
}
|
|
|
- defer resp.Body.Close()
|
|
|
|
|
|
- return resp.StatusCode >= 200 && resp.StatusCode <= 600
|
|
|
+ m.OnlineStatus.Store(upstreamIp, false)
|
|
|
+ m.println("Setting upstream "+upstreamIp+" unreachable for "+strconv.FormatInt(timeout, 10)+"s", nil)
|
|
|
+ go func() {
|
|
|
+ //Set the upstream back to online after the timeout
|
|
|
+ <-time.After(time.Duration(timeout) * time.Second)
|
|
|
+ m.NotifyHostOnlineState(upstreamIp, true)
|
|
|
+ }()
|
|
|
+}
|
|
|
+
|
|
|
+// FilterOfflineOrigins return only online origins from a list of origins
|
|
|
+func (m *RouteManager) FilterOfflineOrigins(origins []*Upstream) []*Upstream {
|
|
|
+ var onlineOrigins []*Upstream
|
|
|
+ for _, origin := range origins {
|
|
|
+ if m.IsTargetOnline(origin.OriginIpOrDomain) {
|
|
|
+ onlineOrigins = append(onlineOrigins, origin)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return onlineOrigins
|
|
|
}
|