'Creating `Uni` from a coroutine / suspending function
We are using quarkus to process messages this run on a regular function
in that we have to call a suspend function
basically
fun process (msg:Message):Message{
val resFrom:Data = runBlocking{fetchDataFromDB(msg.key)}
val processedMsg = processRoutingKey(msg,resFrom)
return processedMsg
}
We would like to get the data as a Uni (https://smallrye.io/smallrye-mutiny/getting-started/creating-unis)
so basically we would like to get back
fun process (msg:Message){
val resFrom:Uni<Data> = ConvertUni {fetchDataFromDB(msg.key)}
}
We need the uni further downstream one time to process some data but we would like to return a Uni from the method meaning
fun process (msg:Message):Uni<Message>{
val resFrom:Uni<Data> = ConvertUni {fetchDataFromDB(msg.key)}
val processed:Uni<Message> =process(msg,resfrom)
return processed
}
Solution 1:[1]
The signature fun process(msg:Message): Uni<Message> implies that some asynchronous mechanism needs to be started and will outlive the method call. It's like returning a Future or a Deferred. The function returns immediately but the underlying processing is not done yet.
In the coroutines world, this means you need to start a coroutine. However, like any async mechanism, it requires you to be conscious about where it will run, and for how long. This is defined by the CoroutineScope you use to start the coroutine, and this is why coroutine builders like async require such a scope.
So you need to pass a CoroutineScope to your function if you want it to start a coroutine that will last longer than the function call:
fun CoroutineScope.process(msg:Message): Uni<Message> {
val uniResult = async { fetchDataFromDB(msg.key) }.asUni()
return process(msg, uniResult)
}
Here Deferred<T>.asUni() is provided by the library mutiny-kotlin. In the examples given in their doc, they use GlobalScope instead of asking the caller to pass a coroutine scope. This is usually a bad practice because it means you don't control the lifetime of the started coroutine, and you may leak things if you're not careful.
Accepting a CoroutineScope as receiver means the caller of the method can choose the scope of this coroutine, which will automatically cancel the coroutine when appropriate, and will also define the thread pool / event loop on which the coroutine runs.
Now, with that in mind, you see that you'll be using a mix of coroutines and Uni at the same level of API here, which is not great. I would advise to instead stick with suspend functions all the way, until you really have to convert to Uni.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Joffrey |
