3

I wonder what is the good practice in Quarkus to run background task per request.

Something like this:

    @POST()
    @Path("v1")
    public Uni<Response> buildSomething() {
        // start a thread to build things in the background
        // when completed, save the id in DB

        // return immediately
        return Uni.createFrom().item(Response.accepted().build());
    }

    @GET()
    @Path("v1")
    public Uni<List<Long>> getSomethingThatHasBeenBuilt() {
        // fetch ids from DB
        return fetchIdsFromDB();
    }

I hope I can do something like a Go routine, for which I can set a timeout and log the error. I suspect one can probably inject a vertx instance and do the task in a worker thread pool, but I don't know how that can be implemented.

GeauxEric
  • 2,814
  • 6
  • 26
  • 33
  • Mutiny in and of itself is already reactive. So if you use a `Uni` or `Multi` in your code to start the computation in the background, it will run concurrently/asynchronously. – Turing85 May 08 '21 at 05:55
  • My process can take up to 10 minute, and I would like to return the response to the client immediately. – GeauxEric May 08 '21 at 05:59
  • Okay, if the task is longrunning, it should not necessarily run on an I/O thread... Is using a framework, like [Quarzt (Quarkus Guide](https://quarkus.io/guides/quartz)) an option? – Turing85 May 08 '21 at 06:10
  • 5
    You can `@Inject org.eclipse.microprofile.context.ManagedExecutor`, which is backed by the Quarkus main worker thread pool, and submit tasks there. Or create your own thread pool, if the tasks can really take multiple minutes. – Ladicek May 08 '21 at 10:15
  • @Ladicek you may want to post that comment of yours as an answer :) – Turing85 May 08 '21 at 17:15
  • Thanks @Ladicek, I end up using that ManagedExecutor to send runnables. – GeauxEric May 08 '21 at 17:21
  • MicroProfile is working on Long Running Actions. I just don't know the status of the project https://microprofile.io/project/eclipse/microprofile-lra – agoncal May 10 '21 at 06:51
  • thanks for the pointer @agoncal. Interesting project to provide different levels of consistency. I already watched the github project. – GeauxEric May 11 '21 at 21:20

1 Answers1

2

The question is whether you want your processing to be "in-and" or "out-of-band":

  1. in-band: your HTTP response must wait for the processing to complete before returning.
  2. out-of-band: your HTTP response is written immediately and your processing runs in the background.

To implement (1), you can:

  • Use Uni and model your code using asynchronous actions like:
return Uni.createFrom(something)
   .chain(s -> doAnotherAsyncAction(s)) // doAnotherAsyncAction returns a Uni
   .chain(s -> yetanotherAsyncAction(s))
  • Use the event bus using a request-reply:
@Inject EventBus bus;
// ...
return bus.request("an-address", someObject)
  .map(Message::body); // the body contains the response
// Somewhere else in your code:
@ConsumeEvent("an-address")
@Blocking
MyResponse process(SomeObject object) {
  // ....
}

To implement (2), you can:

  • Inject and Use the org.eclipse.microprofile.context.ManagedExecutor and submit your tasks as you would do with a regular executor
  • Use the event bus, but instead of request; use send. The @ConsumeEvent side would not return anything (as no one expects a response).

For more details about the event bus, check: https://quarkus.io/guides/reactive-event-bus

Clement
  • 2,817
  • 1
  • 12
  • 11