-
Notifications
You must be signed in to change notification settings - Fork 198
Wire session-aware backend routing and LRU cache-size in proxy transports (RC-12, RC-13) #4212
Description
Description
Switch all three proxy transport constructors (streamable, HTTP-SSE, and transparent) to use session.NewManagerWithRedis, enabling session-sticky routing across multiple proxyrunner replicas (RC-12).
Note: RC-13 (LRU cache-size wiring) has been dropped.
RedisStorage.LoadusesGETEX, which atomically returns session data and refreshes the TTL in a single round-trip, making a local LRU cache layer unnecessary. See #4294 for the rationale.
Parent epic: stacklok/stacklok-epics#263
Dependencies: #4236 (RC-7 — NewManagerWithRedis constructor), #4239 (TASK-001 — RunConfig fields)
Blocks: none (leaf node in the DAG)
Acceptance Criteria
RC-12 — Session-aware routing
-
NewHTTPProxy(streamable): constructs session manager viasession.NewManagerWithRedis; accepts a Redis storage override viaWithSessionStorageoption (defaults tosession.NewLocalStorage()when not provided) -
NewHTTPSSEProxy: same -
NewTransparentProxyWithOptions: same - Transparent proxy
Rewritereads"backend_url"metadata key from session and overridespr.Out.URL; falls back to statictargetURLwhen absent or unparseable - Non-initialize requests with unknown session ID return HTTP 400 in transparent proxy handler
- Existing single-replica behavior preserved when no
WithSessionStorageis provided (defaults toLocalStorage)
General
- All existing tests in
pkg/transport/proxy/streamable/,pkg/transport/proxy/httpsse/, andpkg/transport/proxy/transparent/pass -
go vet ./pkg/transport/proxy/...reports no issues - Tests for transparent proxy
Rewrite: (a)backend_urlin metadata overrides target; (b) nobackend_urlfalls back to static target; (c) unknown session ID on non-initialize returns HTTP 400 - Code reviewed and approved
Technical Approach
RC-12 — Storage wiring
Add WithSessionStorage(storage session.Storage) Option to each proxy constructor. When not provided, default to session.NewLocalStorage(). Pass the storage to session.NewManagerWithRedis:
// At call sites in pkg/transport/http.go, when Redis is configured:
mgr := session.NewManagerWithRedis(redisClient)
// Otherwise fall back to local storage (single-replica default)Extend the transparent proxy Rewrite:
if sid := pr.In.Header.Get("Mcp-Session-Id"); sid != "" {
if sess, ok := p.sessionManager.Get(sid); ok {
if backendURL, _ := sess.GetMetadataValue("backend_url"); backendURL != "" {
if parsed, err := url.Parse(backendURL); err == nil {
pr.Out.URL = parsed
}
}
}
}Code Pointers
pkg/transport/proxy/streamable/streamable_proxy.go:72–98—NewHTTPProxy;session.NewManager→session.NewManagerWithRedispkg/transport/proxy/streamable/streamable_proxy.go:617–621—resolveSessionForBatch; pattern for HTTP 400 on unknown sessionpkg/transport/proxy/httpsse/http_proxy.go:93–120—NewHTTPSSEProxy; same replacementpkg/transport/proxy/transparent/transparent_proxy.go:253–310—NewTransparentProxyWithOptions; session manager wiringpkg/transport/proxy/transparent/transparent_proxy.go:487–513—Rewriteclosure;backend_urloverride injected herepkg/transport/http.go— call sites for both proxy constructors
Out of Scope
- RoutingStorage / LRU cache layer (dropped — see #4294)
RunConfig.SessionCacheSizewiring (no longer needed)- Backend pod selection / round-robin on
initialize - StatefulSet replica count wiring (TASK-002) or graceful shutdown (TASK-003)