WebSocket and gRPC Ingress
flowchart TD
A[WebSocket or gRPC connection fails] --> B{Check ingress transport setting}
B -->|http| C[Set transport: http2 for gRPC]
B -->|http2| D[Check sticky sessions for WebSocket]
C --> E[Redeploy revision]
D -->|Disabled| F[Enable session affinity on ingress]
D -->|Enabled| G[Check upstream app WebSocket handling]
F --> E
G --> E
E --> H[Verify connection succeeds]
Symptom
- WebSocket clients connect but reconnect to a different replica and lose in-memory state.
- gRPC clients fail negotiation or fall back incorrectly when ingress transport is not configured for HTTP/2.
- Teams often report intermittent stream resets even though ordinary HTTP requests still work.
Typical evidence:
- [Observed] Browser or client errors mention upgrade, stream reset, or protocol mismatch.
- [Observed] Ingress configuration shows
transport left at auto or http for a gRPC workload. - [Correlated] Failures become visible only when multiple replicas are active or reconnects occur.
Possible Causes
| Cause | Why it breaks |
gRPC app not using http2 transport | End-to-end HTTP/2 expectations are not explicit. |
| Stateful WebSocket workflow depends on replica stickiness | Reconnects land on a different replica and lose in-memory state. |
| HTTP workload placed on an extra TCP port | Built-in HTTP features such as session affinity are unavailable there. |
| Workload design assumes connection-local state survives failover | Platform routing behaves correctly, but the app is not resilient to replica changes. |
Diagnosis Steps
- Inspect current ingress configuration.
- Confirm whether the workload uses the main HTTP ingress port or an extra TCP port.
- Reproduce with more than one replica to determine whether the issue is transport-related or affinity-related.
az containerapp show \
--name "$APP_NAME" \
--resource-group "$RG" \
--query "properties.configuration.ingress" \
--output json
az containerapp replica list \
--name "$APP_NAME" \
--resource-group "$RG" \
--output table
| Command | Why it is used |
az containerapp show ... --query "properties.configuration.ingress" | Reveals the active ingress transport, target port, and whether sticky session settings exist. |
az containerapp replica list ... | Confirms whether more than one replica is available to expose reconnect and distribution behavior. |
Interpretation:
- [Observed] gRPC plus
transport: http is a direct configuration mismatch. - [Observed] WebSocket reconnect failures that appear only with multiple replicas suggest lost state rather than basic reachability failure.
- [Strongly Suggested] If the app uses an extra TCP port for HTTP semantics, move that traffic back to the main ingress port before debugging higher layers.
Resolution
- Use
transport: http2 for gRPC workloads. - Keep browser-oriented HTTP features, including session affinity, on the main ingress port.
- Enable sticky sessions only when the WebSocket workflow still depends on in-memory replica state.
- Prefer making streaming workloads stateless or externally stateful over relying on affinity indefinitely.
properties:
configuration:
ingress:
external: true
targetPort: 8080
transport: http2
stickySessions:
affinity: sticky
az containerapp update \
--name "$APP_NAME" \
--resource-group "$RG" \
--yaml "websocket-grpc-ingress-fixed.yaml"
| Command | Why it is used |
az containerapp update ... --yaml "websocket-grpc-ingress-fixed.yaml" | Applies the corrected ingress transport and sticky-session settings in one revision-safe update. |
Prevention
- Declare ingress transport explicitly for every gRPC app.
- Keep WebSocket and gRPC state outside the replica when possible.
- Treat sticky sessions as a tactical compatibility aid, not a primary architecture pattern.
- Test reconnect behavior with two or more replicas before production rollout.
See Also
Sources