Browse Source

Fixed sticky session bug

Toby Chui 1 month ago
parent
commit
3e1dc7b974

+ 5 - 0
mod/dynamicproxy/loadbalance/loadbalance.go

@@ -109,6 +109,11 @@ func GetUpstreamsAsString(upstreams []*Upstream) string {
 	return strings.Join(targets, ", ")
 }
 
+// Reset the current session store and clear all previous sessions
+func (m *RouteManager) ResetSessions() {
+	m.SessionStore = sessions.NewCookieStore([]byte(m.Options.SystemUUID))
+}
+
 func (m *RouteManager) Close() {
 	//Close the session store
 	m.SessionStore.MaxAge(0)

+ 1 - 0
mod/dynamicproxy/loadbalance/onlineStatus.go

@@ -67,5 +67,6 @@ func (m *RouteManager) FilterOfflineOrigins(origins []*Upstream) []*Upstream {
 			onlineOrigins = append(onlineOrigins, origin)
 		}
 	}
+
 	return onlineOrigins
 }

+ 32 - 7
mod/dynamicproxy/loadbalance/originPicker.go

@@ -24,7 +24,7 @@ func (m *RouteManager) GetRequestUpstreamTarget(w http.ResponseWriter, r *http.R
 	if useStickySession {
 		//Use stick session, check which origins this request previously used
 		targetOriginId, err := m.getSessionHandler(r, origins)
-		if err != nil || !m.IsTargetOnline(origins[targetOriginId].OriginIpOrDomain) {
+		if err != nil {
 			// No valid session found or origin is offline
 			// Filter the offline origins
 			origins = m.FilterOfflineOrigins(origins)
@@ -39,14 +39,18 @@ func (m *RouteManager) GetRequestUpstreamTarget(w http.ResponseWriter, r *http.R
 				targetOrigin = origins[0]
 				index = 0
 			}
+
+			//fmt.Println("DEBUG: (Sticky Session) Registering session origin " + origins[index].OriginIpOrDomain)
 			m.setSessionHandler(w, r, targetOrigin.OriginIpOrDomain, index)
 			return targetOrigin, nil
 		}
 
 		//Valid session found and origin is online
+		//fmt.Println("DEBUG: (Sticky Session) Picking origin " + origins[targetOriginId].OriginIpOrDomain)
 		return origins[targetOriginId], nil
 	}
 	//No sticky session, get a random origin
+	m.clearSessionHandler(w, r) //Clear the session
 
 	//Filter the offline origins
 	origins = m.FilterOfflineOrigins(origins)
@@ -89,6 +93,20 @@ func (m *RouteManager) setSessionHandler(w http.ResponseWriter, r *http.Request,
 	return nil
 }
 
+func (m *RouteManager) clearSessionHandler(w http.ResponseWriter, r *http.Request) error {
+	session, err := m.SessionStore.Get(r, "STICKYSESSION")
+	if err != nil {
+		return err
+	}
+	session.Options.MaxAge = -1
+	session.Options.Path = "/"
+	err = session.Save(r, w)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 // Get the previous connected origin from session
 func (m *RouteManager) getSessionHandler(r *http.Request, upstreams []*Upstream) (int, error) {
 	// Get existing session
@@ -105,15 +123,22 @@ func (m *RouteManager) getSessionHandler(r *http.Request, upstreams []*Upstream)
 		return -1, errors.New("no session has been set")
 	}
 	originDomain := originDomainRaw.(string)
-	originID := originIDRaw.(int)
+	//originID := originIDRaw.(int)
+
+	//Check if the upstream still exists
+	for i, upstream := range upstreams {
+		if upstream.OriginIpOrDomain == originDomain {
+			if !m.IsTargetOnline(originDomain) {
+				//Origin is offline
+				return -1, errors.New("origin is offline")
+			}
 
-	//Check if it has been modified
-	if len(upstreams) < originID || upstreams[originID].OriginIpOrDomain != originDomain {
-		//Mismatch or upstreams has been updated
-		return -1, errors.New("upstreams has been changed")
+			//Ok, the origin is still online
+			return i, nil
+		}
 	}
 
-	return originID, nil
+	return -1, errors.New("origin is no longer exists")
 }
 
 /* Functions related to random upstream picking */

+ 1 - 0
reverseproxy.go

@@ -595,6 +595,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 	targetProxyEntry.Remove()
+	loadBalancer.ResetSessions()
 	dynamicProxyRouter.AddProxyRouteToRuntime(readyRoutingRule)
 
 	//Save it to file