Ahmed Ibrahim
09/11/2020, 12:50 PMJob
?
suspend <T> fun executeQuery(query: T) {
val deferred = client.queryCall(query).toDeferred()
currentCoroutineContext()[Job]?.invokeOnCompletion {
if (it is CancellationException) {
deferred.cancel(it)
}
}
deferred.await()
}
streetsofboston
09/11/2020, 12:59 PMqueryDeferred
does nor toDeferred
, but it seems that executeQuery
does not do anything in parallel. Just waits for the result of queryDeferred.
suspend fun <T> executeQuery(query: T) {
return queryDeferred(query).toDeferred().await()
}
When the calling scope (CoroutineScope) of executeQuery
is cancelled, the Deferred returned by toDeferred
will be cancelled too, because of Structured Concurrency (depending on how queryDeferred
and toDeferred
are implemented….)Ahmed Ibrahim
09/11/2020, 1:00 PMtoDeferred
is from Apollo's GraphQL coroutine support.
https://github.com/apollographql/apollo-android/blob/master/apollo-coroutines-support/src/main/kotlin/com/apollographql/apollo/coroutines/CoroutinesExtensions.kt#L82queryGenerator.flatMapLatest { query ->
flowOf(executeQuery(query))
}.collect { }
gildor
09/11/2020, 1:10 PMAhmed Ibrahim
09/11/2020, 1:14 PMtoFlow().first()
or I should roll my own solution until it gets fixed?streetsofboston
09/11/2020, 1:14 PMprivate suspend fun <T> ApolloCall<T>.await(): Response<T> =
suspendCancellableCoroutine { cont ->
enqueue(
object : Callback<T>() {
override fun onResponse(response: Response<T>) {
cont.resume(response)
}
override fun onFailure(e: ApolloException) {
cont.resumeWithException(e)
}
}
)
}
basically, the await()
function that Andrey was referring to.Ahmed Ibrahim
09/11/2020, 1:35 PMstreetsofboston
09/11/2020, 1:36 PMawait()
implementation assumes that onResponse
is called at most once! For a more general solution, you’d probably want to add some code around the cont.resume(response)
to guard for this.Ahmed Ibrahim
09/11/2020, 1:54 PMtoDeferred
is designed for a single response and the await
solution is intended to replace it?
AFAIK we have toFlow()
to handle multiple values.streetsofboston
09/11/2020, 2:43 PMApolloCall<T>
is created, when enqueueing the Callback
, its onResponse
m_ay_ get called more than once. In our app, we know that will never happen.
But, in principle, the onResponse
can be called more than once for a given `ApolloCall`… you’d need to guard against that, since cont.resume(value)
can be called at most once.