Open orestesgaolin opened 1 year ago
I was trying to reproduce the problem on the starwars example app, but it works just fine with that:
I/flutter ( 5978): There was an error causing connection lost: SocketException: Connection failed (OS Error: Network is unreachable, errno = 101), address = 10.0.2.2, port = 3000
I/flutter ( 5978): Initialising connection
In case of my CustomWsLink
I was able to capture the exception in onStreamError
of SocketClient
and reconnect as follows. When the WebSocketChannelException
is thrown, the onStreamError
is called and this is how I can react to this by repeatedly trying to reconnect. It's a proof of concept, but for now it seems to work better than without it.
void _connectOrReconnect(String token) {
_connection?.client.dispose();
_connection = _Connection(
client: SocketClient(
url,
// the default implementation does nothing with the exception
onStreamError: (error, stackTrace) {
Logger(tag: 'CustomWsLink').e('Socket error:', error, stackTrace);
Future<void>.delayed(const Duration(milliseconds: 1500))
.then((value) {
_connectOrReconnect(token);
});
},
config: SocketClientConfig(
autoReconnect: true,
inactivityTimeout: const Duration(seconds: 30),
queryAndMutationTimeout: const Duration(seconds: 10),
delayBetweenReconnectionAttempts: const Duration(seconds: 5),
connectFn: (uri, protocols) async {
await getToken();
var channel = WebSocketChannel.connect(uri, protocols: protocols);
// ignore: join_return_with_assignment
channel = channel.forGraphQLIsolate();
return channel;
},
initialPayload: () async {
return {
'headers': {
'Authorization': await getToken(),
'X-Hasura-User-Id': userUid,
'X-Hasura-Role': 'user',
'Content-Type': 'application/json',
},
};
},
),
),
token: token,
);
}
Sorry to be late there, I will try to reproduce it in some of the new demo
From some digging I'm doing ( facing the same problem, errors on the stream are swallowed along the way ) seems the problem is the SocketClient which assumes a default onStreamError which only prints errors. My idea would be to create with a custom websocketlink which passes a streamError function which ( depending on the type of error ) will trigger the reconnect. More on that later.
I can confirm it works. ( after better reading your comments i've seen that you've reached the same conclusions ).
The fix would be to do something like (on WebSocketLink)
@override
void connectOrReconnect() {
_socketClient?.dispose();
_socketClient = graphql.SocketClient(url,
config: config,
protocol: subProtocol,
onStreamError: _reconnectOnNetworkError);
}
_reconnectOnNetworkError(err, stack) {
if (err is NetworkException &&
err.type == NetworkExceptionType.connectionFailure) {
connectOrReconnect();
return;
}
// we have no way of capturing the stream here. if we do nothing the
// error is just swallowed
throw err;
}
This NetworkException is a custom exception that I use on my custom WebSocketChannel, but any other mechanism can be used to detect if it is a recoverable exception or not. Maybe it would make sense to expose a way for users to provide a predicate function where they can decide what is considered to be a recoverable error.
Describe the issue Connection drops with the exception
WebSocketChannelException
and cannot be restored without restarting the app. The problem occurs more or less regularly when the app is idle for at least 20-30 minutes e.g. in the background.To Reproduce
I couldn't find an easy way to reproduce it, but I will try with the example app.
I'm using custom
WebSocketLink
that usescompute
to parse messages and maybe I'm missing something that was already fixed?Expected behavior
The websocket eventually reconnects
device / execution context Happens both on iOS and Android
Other useful/optional fields
Stacktrace:
```dart #0 new IOWebSocketChannel._withoutSocket.Logs:
``` I/flutter (31184): Disconnected from websocket. [log] [DataClient] [38;5;12mπ‘ Token expires at 2022-11-02 17:55:33.000 I/flutter (31184): Initialising connection [log] [DataClient] [38;5;12mπ‘ Token expires at 2022-11-02 17:55:33.000 I/flutter (31184): [SocketClient] message stream encountered error: WebSocketChannelException: WebSocketChannelException: HttpException: Connection reset by peer, uri = https://redacted.hasura.app:0/v1/graphql I/flutter (31184): stacktrace: I/flutter (31184): #0 new IOWebSocketChannel._withoutSocket.additional context
Dependencies:
Flutter doctor