Another fun one... This is weird right? We have a ...
# squarelibraries
c
Another fun one... This is weird right? We have a slim network layer (on top of okhttp) to just make a few things a bit easier. and we have a
Copy code
fun sendSync(req: Req): Res
return runBlocking {
  sendAsync()
}
Copy code
suspend fun sendAsync() {...}
k
You'll almost certainly want
sendAsync
to delegate to
sendSync
and not the reverse. OkHttp isn't non-blocking so a
runBlocking
call wrapping a
sendAsync
will perform much worse than the reverse.
Basically what you've got will be blocking -> suspend -> blocking.
❤️ 1
c
Thanks for teaching!
so what I'll end up with is blocking, suspend instead of block, suspend, block?
k
You should do the following:
Copy code
fun sendSync(request: Request): Response {
  // Call OkHttp. 
}

suspend fun sendAsync(request: Request, context: CoroutineContext): Response {
  withContext(context) { sendSync(...) }
}
This should go suspend -> blocking just once.
❤️ 1
2
g
OkHttp is blocking, but it has own dispatcher, why block more threads if it could be avoided? what is really your use case for sendAsync? Isn't you can just have Req.await() Req.getBlocking()
I also think it's better to optimize for suspend usage, not optimize for blocking (of couse you may have other requirements)
also you need to support cancellation propertly, just wrap withContext() is not great
k
The other requirement I was catering for was that Colton has to offer both a blocking and a suspending API.
g
Yeah, sure, have both in some contexts make sense, what I'm trying to say, that I would sacrifice blocking, and make it suspend first (with no blocking of one more thread, reuse http client dispatcher, support cancellation), and for blocking would be fine to have block dispatcher -> suspend -> block current thread, it doesn't look as a big deal, at least if suspend version is also used In general, have some kind of
Request
(any implementation) abstract and have extension function for suspend/blocking usage is the best way to implement it without compromise of ux and efficiency, though it works only for simple cases when only http request is necessary, if you add other code on top of it, which can be suspend/blocking, it causes the same dilema again. Anyway, I think suspend must be prioritized, it's more safe (structured concurrency, no accidental thread blocking), flexible, supports cancellation, and blocking can be a wrapper, if it not even the most efficient one
c
"what is really your use case for sendAsync?" we're writing a small layer on top of okhttp just to abstract away the network client. as we explored okhttp it has a recipes section for sync get and async get, so the team (not me) copied that approach. thats basically "why" we have sync and async. https://square.github.io/okhttp/recipes/#synchronous-get-kt-java
definitely some interesting points you made there Andrey. I will have to consider while refactoring. personally i would also only go the async route with a suspend function and if the user/caller of the library (that im building) wants "synchrnous" network request for whatever reason then I guess they can just wrap the suspend function with runBlocking themselves.
👍 1