We started a new project with Quarkus
and Mutiny
, and created a bunch of endpoints with Quarkus @Funq
, everything has been working fine so far. Now we want to process something very time-consuming in one of the endpoints, and what we are expecting is, once user clicks a button to send the http request from frontend and hits this specific endpoint, we are going to return 202 Accepted
immediately, leaving the time-consuming operation processing in another thread from backend, then send notification email accordingly to user once it completes.
I understand this can be done with @Async
or CompletableFuture
, but now we want to do this with Mutiny
. Based on how I read Mutiny
documentation here https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive, runSubscriptionOn
will avoid blocking the caller thread by running the time-consuming method on another thread, and my testing showed the time-consuming codes did get executed on a different thread. However, the http request does not
return immediately, it is still pending until the time-consuming method finishes executing (as I observe in the browser's developer tool). Did I misunderstand how runSubscriptionOn
works? How do I implement this feature with Mutiny
?
My @Funq
endpoint looks like this
@Inject
MyService myService;
@Funq("api/report")
public Uni<String> sendReport(MyRequest request) {
ExecutorService executor = Executors.newFixedThreadPool(10, r -> new Thread(r, "CUSTOM_THREAD"));
return Uni.createFrom()
.item(() -> myService.timeConsumingMethod(request))
.runSubscriptionOn(executor);
}
Edit: I found the solution using Uni
based on @Ladicek's answer. After digging deeper into Quarkus and Uni I have a follow-up question:
Currently most of our blocking methods are not
returning Uni on Service
level, instead we create Uni object from what they return (i.e. object or list), and return the Uni on Controller
level in their endpoints like this
return Uni.createFrom().item(() -> myService.myIOBlockingMethod(request))
.
As @Ladicek explained, I do not have to use .runSubscriptionOn
explicitly as the IO blocking method will automatically run on a worker thread (as my method on Service level does not
return Uni). Is there any downside for this? My understanding is, this will lead to longer response time because it has to jump between the I/O thread and worker thread, am I correct?
What is the best practice for this? Should I always return Uni
for those blocking methods on Service
level so that they can run on the I/O threads as well? If so I guess I will always need to call .runSubscriptionOn
to run it on a different worker thread so that the I/O thread is not blocked, correct?
myService.timeConsumingMethod(request)
did get executed on a different thread rather than the main thread when usingrunSubscriptionOn
as described in Mutiny documentation . What I do not understand is, why the response does not return immediately, even with the time-consuming method being executed on a different thread? I am new toMutiny
and would appreciate if you could be more specific to help me understand this. – Athena