apollo-ios
apollo-ios copied to clipboard
Unable to resume websocket connection after pausing/closing
Bug report
Unable to resume websocket connection and receive events after pausing/closing the connection.
Versions
Please fill in the versions you're currently using:
apollo-iosSDK version: 0.47.1- Xcode version: 12.5.1
- Swift version: 5
- Package manager: Cocoapods
Steps to reproduce
- Create/setup apollo clientt
- Resume websocket connection and begin receiving events
- Pause/close websocket connection to stop receiving events
- Resume websocket connection again to begin receiving events again
- Unable to receive websocket events
Further details
We receive websocket events on a single screen in our app. When we create/setup our apollo client, we pass in a value of false for the connectOnInit param for the WebSocketTransport because we want to have control over pausing/resuming websocket events and only receive them when the user is viewing this specific screen.
When the user visits this screen, we check if the websocket is connected and if it's not, then we call resumeWebSocketConnection to begin receiving events. This works fine the first time the user visits this screen.
When the user leaves the screen, the view controller's deinit function is called and we call pauseWebSocketConnection on the websocket transport to stop receiving events (have also tested closeConnection with similar results).
We receive the following error as expected, just as described in the apollo docs, when we pause the connection:
"websocket is disconnected: WSError(type: Apollo.WebSocket.WSError.ErrorType.protocolError, message: \"\", code: 1000)"
When the user revisits the screen, we check the connection again and if it's not connected (it shouldn't be), then we call resumeWebSocketConnection on the websocket transport to begin receiving events again. However this time, we receive the following error:
Error with subscription result: Websocket network error. Error: Optional(Apollo.WebSocket.WSError(type: Apollo.WebSocket.WSError.ErrorType.protocolError, message: "", code: 1000))
From this point on we are unable to receive websocket events.
Here is our apollo client setup/creation code:
// Setup HTTP transport
let client = URLSessionClient()
let provider = NetworkInterceptorProvider(client: client, store: store)
self.httpTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: httpsUrl)
// Setup websocket transport
let request = URLRequest(url: wssUrl)
let webSocket = WebSocket(request: request)
self.webSocketTransport = WebSocketTransport(websocket: webSocket, connectOnInit: false)
self.webSocketTransport.updateHeaderValues(["Authorization": APIManager.sharedInstance().authToken], reconnectIfConnected: false)
// Setup split network transport
self.splitNetworkTransport = SplitNetworkTransport(
uploadingNetworkTransport: self.httpTransport,
webSocketNetworkTransport: self.webSocketTransport
)
// Initialize client
self.client = ApolloClient(networkTransport: splitNetworkTransport, store: store)
Here is how we check the connection and resume if necessary:
if !APIClient.shared.webSocketTransport.isConnected() {
APIClient.shared.webSocketTransport.resumeWebSocketConnection()
}
Here is how we pause/close the websocket connection in the view controllerr:
deinit {
APIClient.shared.webSocketTransport.closeConnection()
APIClient.shared.watcherCancel()
self.subscription?.cancel()
}
Looks like if you want to reopen the same connection, you should be calling pauseWebSocketConnection() rather than closeConnection() - close connection sends a message completely terminating the socket before disconnecting, so reconnecting isn't really possible after that.
Looks like if you want to reopen the same connection, you should be calling
pauseWebSocketConnection()rather thancloseConnection()- close connection sends a message completely terminating the socket before disconnecting, so reconnecting isn't really possible after that.
@designatednerd Sorry to be clear we get the same results with both close/pause. Calling pauseWebSocketConnection() produces the same results.
Ah yes, that's less expected then! From the code it does appear that you've got the URLSessionClient in a singleton so it shouldn't be getting hammered by ARC. Is this just the user going in and out of the screen without ever exiting the app, or does it require the user to background the app?
If you have time a little reproduction of this would be super-helpful!
I've been able to reproduce something similar to this by backgrounding the app and locking the phone, it doesn't always happen, maybe 50% of the time?
This issue should be fixed with https://github.com/apollographql/apollo-ios/pull/2449.