Neal Sanche
06/01/2021, 5:48 PMNeal Sanche
06/01/2021, 6:56 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 PMrocketraman
06/01/2021, 8:15 PMMainScope()
CoroutineScope
. That worked perfectly on both Android and iOS.Neal Sanche
06/01/2021, 8:54 PMNeal Sanche
06/01/2021, 8:55 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)
Neal Sanche
06/01/2021, 10:11 PMprivate suspend fun onUnsubscribed() {
mutex.withLock {
if (--activeSubscriptionCount == 0 && idleTimeoutMs > 0) {
/*
idleTimeoutJob?.cancel()
connectionKeepAliveTimeoutJob?.cancel()
idleTimeoutJob = coroutineScope.launch {
delay(idleTimeoutMs)
close()
}
*/
}
}
}
Neal Sanche
06/01/2021, 10:12 PMNeal Sanche
06/01/2021, 10:37 PMApolloWebSocketNetworkTransport.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.Neal Sanche
06/01/2021, 10:44 PMcoroutineScope
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.Neal Sanche
06/01/2021, 11:04 PMexecutionContext
parameter to the execute
method here is what stopped the crashes that I was seeing. I absolutely need the flowOn
as well.Neal Sanche
06/01/2021, 11:06 PMUncaught Kotlin exception: com.apollographql.apollo.ApolloWebSocketException: Failed to establish GraphQL websocket connection with the server, timeout.
Neal Sanche
06/01/2021, 11:06 PMkfun:com.apollographql.apollo.network.ws.ApolloWebSocketNetworkTransport.$openServerConnectionCOROUTINE$22.invokeSuspend#internal + 1269
Neal Sanche
06/01/2021, 11:08 PMNeal Sanche
06/02/2021, 3:02 PMgetServerConnection
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.Neal Sanche
06/02/2021, 3:04 PMflow {}
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
}
})
}
}
Neal Sanche
06/02/2021, 3:25 PMrocketraman
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 PMNeal Sanche
06/02/2021, 3:34 PMNeal Sanche
06/02/2021, 5:57 PMNeal Sanche
06/02/2021, 7:44 PMNeal Sanche
06/02/2021, 9:49 PMNeal Sanche
06/02/2021, 9:58 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.