What's the 'proper' way to bridge coroutines and a...
# coroutines
r
What's the 'proper' way to bridge coroutines and a 3rd-party library (smallrye-mutiny)? I'd like to be able to do something like:
Copy code
@GET
suspend fun get(): Uni<String> = uni { getFoo() } // run coroutine and return the result as a "Uni", which is similar to Reactor's Mono.
The existing 3rd-party helpers in kotlinx.coroutines' rely on
AbstractCoroutine
, which warns that it shouldn't be used outside of the core lib. (e.g. mono builder)
Should I: 1. Find a way to implement the same behaviour without using
AbstractCoroutine
2. Use
AbstractCoroutine
and pray it doesn't break 3. Make an issue on the kotlinx.coroutines repo and hope they make an official set of Mutiny helpers?
or if it can integrate with
CompletableFuture
you can use the java8 integration library
looking at the api the suspend cancellable coroutine would be the way to go IMO
Copy code
suspend fun get(): Uni<String> = suspendCancellableCoroutine { continuation ->

request
    .ifNoItem().after(ofSecond(1))
        .fail(() -> new Exception("💥"))
    .onFailure().recoverWithItem(fail -> continuation.resumeWithException(fail))
    .subscribe()
        .with(item -> continuation.resumeWith(item))
}
something like that
y
That library has bindings to RxJava(/3) and Reactor. Can't you use the kotlin coroutines support for those libraries?
Basically if you can find a way to not be the one implementing suspendCancellableCoroutine it's a good thing. There are a lot of ways to get it slightly wrong.
😅 1
r
@yschimke: Mutiny is an alternative to RxJava and Reactor that's used by Quarkus. While it may be possible to chain together conversions like Mutiny -> Reactor -> coroutines, I was hoping to improve the experience of using Kotlin with Quarkus.
👍🏻 1
y
It says its based on reactive stream spec so link above should still work I thought. But I missed that context.
r
I probably could have explained it better. I've been jumping between several different projects and computers over the past few days, so my thoughts are a bit scattered. 😅
@Justin Tullgren: I'm actually trying to accomplish the opposite: create and complete/fail a Uni based on the execution of a coroutine. My naive implementation was something like below, but the code in
launch
never actually runs.
Copy code
fun <T> CoroutineScope.uni(block: suspend CoroutineScope.() -> T): Uni<T> {
  Uni.createFrom().emitter<T> { em ->
    // Need to call launch because "Suspension functions can be called only within coroutine body".
    launch {
      try {
        em.completed(block())
      } catch(ex: Exception) {
        // I know that swallowing CancellationException is bad
        em.fail(t)
      }
    }
  }
}
The existing bindings seem to have the same challenge, and solve it with
AbstractCoroutine
.