I'm attempting to convert a blocking function from...
# coroutines
m
I'm attempting to convert a blocking function from an API to a suspending call. After doing a lot of research, what I've found is that I should use
withContext(<http://Dispacters.IO|Dispacters.IO>)
(for I/O functions). For example, more specifically, I'm attempting to convert the
fetch()
from jOOQ to a suspending function:
Copy code
suspend fun <R : Record> ResultQuery<R>.await(): Result<R> =
    withContext(<http://Dispatchers.IO|Dispatchers.IO>) { fetch() }
Is this the correct way of going about this?
e
https://www.jooq.org/doc/latest/manual/sql-execution/fetching/reactive-fetching/ could be better; asFlow will convert a
ResultQuery<R>
into a
Flow<R>
m
Is that simply doing the same kind of thing, though, as
withContext(Dispatcher)
under the hood?
e
no, you'd still want a
.flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
that way
but it would allow for not tying up a thread performing a blocking fetch, if the underlying publisher is truly async
m
I see. I guess I'm still not versed enough in the underlying nature of coroutines. Are you able to explain how Kotlin waits for the result on something like this without blocking a thread? Is it a native function of the language? To my knowledge, even an async program still has to block dedicated I/O threads to wait for something like a database
e
with R2DBC a dedicated thread isn't required
with
.asFlow()
, Kotlin suspends (allowing the underlying thread to handle other coroutines) until upstream publishes another record
jOOQ documentation looks like it'll still block if you're using that API with a backend that doesn't support async. not clear to me if it blocks the current thread or one from its own threadpool, though
m
Yeah that's what I'm seeing as well. Seems as though I need to include that driver; I'll have to read more on that. I appreciate the information
Furthermore, if the underlying API doesn't support the reactive Publisher (e.g. outside of jOOQ etc.), what is the best way to convert a blocking function to suspending? To somehow wrap it as a Flow?
e
depends. if it's a single operation then it should just be a
suspend fun
. if it returns multiple results then a
Flow<*>
is better (and functions returning
Flow
should generally not be
suspend
themselves)
but ideally whatever you're wrapping has an async API. if it's callback-based, then you can use
suspendCancellableCoroutine
or
callbackFlow
to adapt it. if it's using Java8 futures, Java9 publishers, Reactive Streams, RxJava, etc… then there's already adapters that exist
m
Okay that makes sense. I'm guessing then the final fallback would be
withContext
to block a thread and suspend until the blocking function returns?
e
well, the coroutine doesn't suspend in that case, but yes
m
To clarify, wouldn't it suspend the coroutine being run by thread A and instead block thread B while thread A still does work? It doesn't make sense that it wouldn't suspend the coroutine (it says it does in IntelliJ)
e
withContext
does suspend on the original dispatcher, but then the coroutine on the
IO
dispatcher is blocking, not suspending
m
Okay yes that makes sense
Thanks for all the info
g
also if blocking operatioon supports interruption, you may concider to wrap it with https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-interruptible.html
e
good point, I forgot to mention