Neal Sanche
06/01/2021, 5:48 PMUncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen com.apollographql.apollo.network.ws.ApolloWebSocketNetworkTransport@6f8e68
I am going to try to refactor things so that instead of using a kotlin object
as the source of the ApolloClient instances, I will use koin
instead. Not sure if that's going to change the outcome, here, but it's worth a try I suppose.rocketraman
06/01/2021, 8:13 PMMainScope()
CoroutineScope
. That worked perfectly on both Android and iOS.Neal Sanche
06/01/2021, 8:54 PMUncaught Kotlin exception: kotlin.native.concurrent.FreezingException: freezing of Continuation @ $onUnsubscribed$<anonymous>_6COROUTINE$16 has failed, first blocker is ArrayChannel@147048{ReceiveQueued}(buffer:capacity=64,size=0)
private suspend fun onUnsubscribed() {
mutex.withLock {
if (--activeSubscriptionCount == 0 && idleTimeoutMs > 0) {
/*
idleTimeoutJob?.cancel()
connectionKeepAliveTimeoutJob?.cancel()
idleTimeoutJob = coroutineScope.launch {
delay(idleTimeoutMs)
close()
}
*/
}
}
}
ApolloWebSocketNetworkTransport.kt
I find that the iOS app crashes if there is any code in this lambda:
idleTimeoutJob = coroutineScope.launch {
delay(idleTimeoutMs)
close()
}
If I leave the delay
or the close()
in there, we have the same crash as above, a FreezingException. There is only two places in this code where coroutines are launched. I'm going to do some experimentation.coroutineScope
being used here, I found the execute() method can take a dispatcher, and I was able to get this subscription working using that. Testing some more to ensure it wasn't a fluke.executionContext
parameter to the execute
method here is what stopped the crashes that I was seeing. I absolutely need the flowOn
as well.Uncaught Kotlin exception: com.apollographql.apollo.ApolloWebSocketException: Failed to establish GraphQL websocket connection with the server, timeout.
kfun:com.apollographql.apollo.network.ws.ApolloWebSocketNetworkTransport.$openServerConnectionCOROUTINE$22.invokeSuspend#internal + 1269
getServerConnection
method of ApolloWebSocketNetworkTransport which creates a flow that internally calls openServerConnection
. That method can throw ApolloWebSocketException. Those exceptions crash the app unless they are caught. Naively I added the following code to suppress them:
private fun getServerConnection(dispatcherContext: ApolloCoroutineDispatcherContext): Flow<GraphQLWebsocketConnection> {
return flow {
val connection = mutex.withLock {
if (graphQLWebsocketConnection?.isClosedForReceive() != false) {
graphQLWebsocketConnection = openServerConnection(dispatcherContext)
}
graphQLWebsocketConnection
}
emit(connection)
}
.catch { emit(null)}
.filterNotNull()
}
the catch
at the bottom emits null which is immediately filtered. But this ultimately fixes the crash I'm currently seeing.flow {}
builder doesn't seem to have an emit error functionality though.rocketraman
06/02/2021, 3:05 PMResult
?Neal Sanche
06/02/2021, 3:12 PMrocketraman
06/02/2021, 3:13 PMFlow<Result<GraphQLWebsocketConnection>>
, yeahNeal Sanche
06/02/2021, 3:22 PMprivate fun getServerConnection(dispatcherContext: ApolloCoroutineDispatcherContext): Flow<Result<GraphQLWebsocketConnection?>> {
return flow {
emit(kotlin.runCatching {
mutex.withLock {
if (graphQLWebsocketConnection?.isClosedForReceive() != false) {
graphQLWebsocketConnection = openServerConnection(dispatcherContext)
}
graphQLWebsocketConnection
}
})
}
}
rocketraman
06/02/2021, 3:26 PMNeal Sanche
06/02/2021, 3:26 PMrocketraman
06/02/2021, 3:27 PMNeal Sanche
06/02/2021, 3:29 PMcatch
operator if errors in connection need to be sent along with the rest of the flow. If it doesn't matter, the flow will just finish if the server can't be contacted, so nothing needs to be emitted.