Add WebSession-based sticky load balancing filter - #4234
Open
Gebreyesus wants to merge 1 commit into
Open
Conversation
Gebreyesus
force-pushed
the
feature/session-based-sticky-loadbalancer
branch
from
July 8, 2026 22:01
cff3f91 to
fb61cc5
Compare
Member
|
Without having reviewed this at all, I'm not sure a new scheme is the way to configure this |
…eLoadBalancerClientFilter passes a RequestDataContext to the load balancer, carrying no reference to the ServerWebExchange or WebSession. This makes it impossible for a custom ReactorServiceInstanceLoadBalancer to implement per-route, server-side session affinity without fully replacing the default filter. This commit adds: WebSessionStickyLoadBalancerFilter: a GlobalFilter that handles routes with the sticky:// URI scheme. Sets IS_STICKY_ATTRIBUTE on the exchange, passes the raw ServerWebExchange as load-balancer context, and rewrites the request URI to the chosen instance. Runs at the same order as ReactiveLoadBalancerClientFilter (10150). lb:// routes are not affected. WebSessionStickyLoadBalancer: a ReactorServiceInstanceLoadBalancer that stores a serviceId->instanceId affinity map in the gateway WebSession. Reuses the pinned instance while registered; transparently re-pins via round-robin if the instance is deregistered or fails a health check. Falls through to the delegate for non-sticky exchanges and for any context that is not a ServerWebExchange (e.g. internal WebClient calls). WebSessionStickyGatewayFilterFactory: a per-route GatewayFilter that enables the same sticky behavior while keeping lb:// as the URI scheme. Routes add - WebSessionSticky to their filter list. This is the composable alternative to the sticky:// scheme approach. choose() uses the 2-arg getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class) overload, matching ReactiveLoadBalancerClientFilter, so a WebSessionStickyLoadBalancer configured via @LoadBalancerClient is resolved correctly per service. GatewayReactiveLoadBalancerClientAutoConfiguration wires both beans, disabled by default: spring.cloud.gateway.global-filter.web-session-sticky-load-balancer.enabled=true Routes opt in per-route via either: uri: sticky://my-service or: filters: - WebSessionSticky Documentation added to global-filters.adoc and gatewayfilter-factories/websessionsticky-factory.adoc. Related upstream gap: spring-cloud/spring-cloud-commons#764 and spring-cloud#1176. Signed-off-by: Beteab G. Gebreyesus <beteab@live.com>
Gebreyesus
force-pushed
the
feature/session-based-sticky-loadbalancer
branch
from
July 12, 2026 22:22
c82577d to
8a4bba3
Compare
Author
@spencergibb Agreed. When this filter is applied to a route, every client session is pinned to a specific backend instance for the duration of that session. Affinity is maintained server-side in the gateway WebSession. No new URI scheme required. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
/legacy/**requests are pinned to one instance per client session./api/**requests use normal round-robin. Same service, different behavior per route.WebSessionStickyLoadBalancerA
ReactorServiceInstanceLoadBalancerthat:serviceId -> instanceIdaffinity map from the gatewayWebSessionWebClientcalls)WebSessionStickyLoadBalancerFilter(alternative opt-in)A
GlobalFilterthat handles routes using thesticky://URI scheme as an alternative to the GatewayFilter approach. Disabled by default.Key design decisions
WebSession, not in a client cookie- WebSessionStickyfilter (orsticky://scheme)getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class)so aWebSessionStickyLoadBalancerwired via@LoadBalancerClientis resolved correctly per serviceFiles changed
WebSessionStickyGatewayFilterFactory.javaWebSessionStickyLoadBalancer.javaWebSessionStickyLoadBalancerFilter.javaGatewayReactiveLoadBalancerClientAutoConfiguration.javaWebSessionStickyLoadBalancerTests.javaWebSessionStickyLoadBalancerFilterTests.javaWebSessionStickyGatewayFilterFactoryTests.javaglobal-filters.adocwebsessionsticky-factory.adocnav.adocTesting
ReactiveLoadBalancerClientFilterTestsandLoadBalancerServiceInstanceCookieFilterTestspass without modificationChecklist
.javafiles@authortags on new and modified filesSigned-off-byon commitRelated: #1176, spring-cloud/spring-cloud-commons#764