Description
When network connectivity becomes unstable, the WebSocket reconnect flow can enter a state where incoming subscription messages are still being received from AppSync, but they are never delivered to subscription listeners.
After investigating the source code and debugging the internal WebSocket implementation of Amplify, it appears that the reconnect workflow blocks the entire WebSocket event processing pipeline.
Observed Behavior
- App starts with active GraphQL subscriptions
- Network becomes slow/intermittent (I used Network link conditioner to test it)
- Connectivity reports a disconnect and NetworkLossEvent is emitted
- ReconnectEvent is added and
_reconnect() begins executing
- While
_reconnect() is running, AppSync continues sending and ARE received by the WebSocketService:
KeepAliveEvent
SubscriptionDataEvent
AmplifyWebSocketService._onData() receives these events successfully.
WebSocketBloc._safeAdd() is called successfully.
_wsEventController.add(event) is executed successfully.
- However,
WebSocketBloc._eventTransformer() is never entered for these events.
As a result:
- Subscription updates stop reaching application code.
- Incoming realtime events are effectively frozen.
- The socket appears healthy enough to continue receiving data, but the events are not processed
After investigating the whole behavior, when a ReconnectEvent is emitted, and taking too long to complete, all healthy, incoming events are queued behind the reconnect operation.
The issue lies here:
final blocStream = _wsEventStream.asyncExpand(_eventTransformer);
asyncExpand processes events sequentially, the running ReconnectEvent appears to block all subsequent events from being processed.
The expected behavior here is that incoming WebSocket messages should continue to be processed while reconnect logic is running, especially if:
- The WebSocket connection is still receiving keep-alive messages.
- Subscription data messages are still arriving from AppSync.
A reconnect attempt should not block processing of valid incoming subscription traffic like SubscriptionDataEvent, KeepAliveEvent, ConnectionAckMessageEvent and others
Isn't better for reconnect operations be performed outside the main event processing queue?
Categories
Steps to Reproduce
- Create a subscription
- Simulate a very slow internet connection with high RetryOptions max attempts so that a Reconnect operation keeps running
- Execute a mutation for that subscription
- Observe under verbose logging that the WebSocketService received the Data event and keeps receiving KeepAliveEvents but the WebSocketBloc does not.
Screenshots
No response
Platforms
Flutter Version
3.44
Amplify Flutter Version
2.11.0
Deployment Method
Amplify CLI (Gen 1)
Schema
Description
When network connectivity becomes unstable, the WebSocket reconnect flow can enter a state where incoming subscription messages are still being received from AppSync, but they are never delivered to subscription listeners.
After investigating the source code and debugging the internal WebSocket implementation of Amplify, it appears that the reconnect workflow blocks the entire WebSocket event processing pipeline.
Observed Behavior
_reconnect()begins executing_reconnect()is running, AppSync continues sending and ARE received by the WebSocketService:KeepAliveEventSubscriptionDataEventAmplifyWebSocketService._onData()receives these events successfully.WebSocketBloc._safeAdd()is called successfully._wsEventController.add(event)is executed successfully.WebSocketBloc._eventTransformer()is never entered for these events.As a result:
After investigating the whole behavior, when a ReconnectEvent is emitted, and taking too long to complete, all healthy, incoming events are queued behind the reconnect operation.
The issue lies here:
final blocStream = _wsEventStream.asyncExpand(_eventTransformer);asyncExpandprocesses events sequentially, the running ReconnectEvent appears to block all subsequent events from being processed.The expected behavior here is that incoming WebSocket messages should continue to be processed while reconnect logic is running, especially if:
A reconnect attempt should not block processing of valid incoming subscription traffic like SubscriptionDataEvent, KeepAliveEvent, ConnectionAckMessageEvent and others
Isn't better for reconnect operations be performed outside the main event processing queue?
Categories
Steps to Reproduce
Screenshots
No response
Platforms
Flutter Version
3.44
Amplify Flutter Version
2.11.0
Deployment Method
Amplify CLI (Gen 1)
Schema