feat(gateway-api): allow header-based sticky session (ConsistentHash.Header)#746
Conversation
Allow clients that cannot persist cookies (e.g. MCP SDK clients keying off `Mcp-Session-Id`) to benefit from session affinity by letting users pick a request header to hash on. When `network.gateway_api.sticky_session_header` is set (and `network.gateway_api.enable_sticky_session` is true), the generated BackendTrafficPolicy uses `consistentHash.type: Header` instead of the default `Cookie`. The existing cookie-based behavior is unchanged when the setting is left unset (null), preserving backward compatibility for all current users. Use case: MCP servers (Model Context Protocol) need sticky routing on `Mcp-Session-Id` because their clients (n8n, Claude Desktop, MCP Inspector, etc.) do not implement HTTP cookie storage — they key sessions off a single request header per the MCP spec. Without header-based affinity, stateful MCP servers cannot scale past one replica behind Qovery's gateway. Applies to both HTTPRoute and GRPCRoute BackendTrafficPolicy templates.
47c8a31 to
1d1cfcb
Compare
|
Thanks for this contribution, it makes total sense and we would love to integrate this. I made couple comments on the PR. Some changes, especially the Cheers |
There was a problem hiding this comment.
suggestion: remove this file
| @@ -161,6 +161,8 @@ pub struct ApplicationAdvancedSettings { | |||
| // Gateway API | |||
| #[serde(alias = "network.gateway_api.enable_sticky_session")] | |||
| pub network_gateway_api_sticky_session_enable: bool, | |||
| #[serde(default, alias = "network.gateway_api.sticky_session_header")] | |||
| pub network_gateway_api_sticky_session_header: Option<String>, | |||
There was a problem hiding this comment.
suggestion: since this can be now either Cookie or Header, let's push a little bit further and allow the last type SourceIP doc
Hence, let's introduce an enum here:
You can put it here for the time being and import it in the other files
pub enum StickyHeaderType {
Cookie,
Header { name: String },
SourceIp,
}Then, templates need to be updated as well
There was a problem hiding this comment.
suggestion: remove this file
There was a problem hiding this comment.
suggestion: remove this file
There was a problem hiding this comment.
suggestion: remove this file
6552db2 to
6b72945
Compare
Summary
Adds a new service advanced setting
network.gateway_api.sticky_session_headerthat switches the generatedBackendTrafficPolicy.loadBalancer.consistentHashfromCookietoHeaderwhen set.The existing cookie-based affinity (
INGRESSCOOKIE_QOVERY) is the default and remains unchanged when the setting is unset (null) — fully backward compatible.Motivation
Cookie-based affinity is unusable for clients that cannot persist HTTP cookies:
Mcp-Session-Idheader per spec.fetch()/undiciwithout cookie jar support, soSet-Cookiefrom the ingress is simply dropped.The same applies to any HTTP client that uses bearer-token auth + a custom session header (common in gRPC + metadata, or internal microservices).
Changes
network_gateway_api_sticky_session_header: Option<String>toApplicationAdvancedSettings,ContainerAdvancedSettings, andHelmChartAdvancedSettingswith serde aliasnetwork.gateway_api.sticky_session_header.ApplicationAdvancedSettings::to_container_advanced_settings.ConsistentHash.Headerwhen the setting is non-empty, keep the existing Cookie branch otherwise.tests/helm/mod.rsstruct literals to include the new field (defaults toNone, no behavior change).Backward compatibility
Zero behavior change for existing users: the setting defaults to
None, which preserves the currentINGRESSCOOKIE_QOVERYcookie-based ConsistentHash.Test plan
cargo checkpasses (verified locally — 2m04s).cargo check --testspasses (verified locally — 1m18s, alltests/helm/mod.rsstruct literals compile).engine-public).network.gateway_api.sticky_session_header = "Mcp-Session-Id"on a 3-replica backend, verify successive requests with the same header value hit the same pod.