Asif Ahmed
03/08/2024, 12:56 PMApiClient
for blocking calls. Due to certain limitations, adopting a fully reactive approach isn’t feasible at the moment. However, we are keen on finding a middle ground to improve performance through parallel calls.
To achieve this, we are exploring Kotlin Coroutines(We have also explored CompletableFuture and @Asyc but not happy with it ). As a relative newcomer to coroutines, I’ve implemented a solution that seems to work, but I’m uncertain if it’s the optimal approach. Below is a simplified snippet of the current implementation:
@Service
class Service(
private val clientA: ClientA,
private val clientB: ClientB,
private val clientC: ClientC
) {
fun someFunction(): OrderForm {
runBlocking(RequestCoroutineContext()) {
val result1 = async(Dispatchers.IO) { callA() }
val result2 = async(Dispatchers.IO) { callB() }
val result3 = async(Dispatchers.IO) { callC(result1.await()) }
OrderForm(result1.await(), result2.await(), result3.await())
}
}
private suspend fun callA() = clientA.get()
private suspend fun callB() = clientB.get()
private suspend fun callC(value: SomeType) = clientC.get(value)
}
Initially, the ApiClient
methods were not marked as suspend
, but I’m now considering moving towards making these calls suspendable to bring them closer to the client:
class ClientA {
suspend fun getA() {
withContext(Dispatchers.IO) {
// blocking API call
}
}
}
class ClientB {
suspend fun getB() {
withContext(Dispatchers.IO) {
// blocking API call
}
}
}
class ClientC {
suspend fun getC(value: SomeType) {
withContext(Dispatchers.IO) {
// blocking API call
}
}
}
However, attempting to call these suspendable functions in someFunction()
resulted in an exception
Handler dispatch failed: java.lang.NoClassDefFoundError: kotlinx/coroutines/reactor/MonoKt","stack_trace":"jakarta.servlet.ServletException: Handler dispatch failed: java.lang.NoClassDefFoundError: kotlinx/coroutines/reactor/MonoKt
related to NoClassDefFoundError: kotlinx/coroutines/reactor/MonoKt
. I suspect this may be due to the fact that the actual API calls are not reactive and suspendable.
I’m seeking recommendations on the best way to handle coroutines in a single thread per request model with Spring Boot. I want to avoid marking private functions as suspended and continually wrapping code in scopes.
Any insights or guidance would be greatly appreciated.Robert Jaros
03/08/2024, 1:12 PMorg.jetbrains.kotlinx:kotlinx-coroutines-reactor
dependency should help with these errors.Asif Ahmed
03/08/2024, 1:19 PMRobert Jaros
03/08/2024, 1:25 PMrunBlocking
just to call blocking API with <http://Dispatchers.IO|Dispatchers.IO>
. I'm not a Spring expert, but how could this improve performance? 🙂Asif Ahmed
03/08/2024, 1:38 PMasync(<http://Dispatchers.IO|Dispatchers.IO>) { callA() }
in context with withContext(<http://Dispatchers.IO|Dispatchers.IO>)
will use the spawned thread from async and doesn’t use its own pool rightDavid Kubecka
03/08/2024, 1:46 PMrunBlocking
scope:
runBlocking(RequestCoroutineContext() + <http://Dispatchers.IO|Dispatchers.IO>) {
val result1 = async { callA() }
David Kubecka
03/08/2024, 1:49 PMKlitos Kyriacou
03/08/2024, 1:56 PM<http://Dispatchers.IO|Dispatchers.IO>
use Java threads in the same way as CompletableFuture
does.Asif Ahmed
03/08/2024, 2:07 PMJacob
03/08/2024, 6:51 PMJacob
03/08/2024, 6:52 PMAsif Ahmed
03/11/2024, 5:50 AM