kotlinquarkusbackground-processnonblockingquarkus-rest-client

Run background task in Quarkus after REST API returns response


I have a Quarkus with Kotlin application that exposes a bunch of REST APIs. I'd like to have an endpoint which would be able to trigger the processing of a task (which runs in the background), and the API response should be returned - whilist the background task runs (Result of the background task is not required). I'd like to know what is the best way to accomplish this in a production setting. Also, some amount of data is to be transfered to the background process funciton as seen in the example below:

@Path("test")
@GET
fun test() : Response{

    // Step 1: Do some processing and get a result

    backgroundProcessResult() // Step 2: This should be done without 
                              // blocking the subsequent steps and API response.

    // Step 3: Further processing...

    // Step 4: Return back the API response
    return Response.ok().build()
}

Here are the options that I have come across so far:

  1. Event Bus
  2. Kotlin Coroutines (Can't be used due to issue mentioned here)

I'm open to using other ways to handle this too. What's the right way to handle this in a production application?


Solution

  • The easiest way is by making use of a ManagedExecutor:

        @Inject
        @ManagedExecutorConfig(maxAsync = 10)
        ManagedExecutor executor;
    
        @GET
        @Path("test")   
        public Response void test() {
    
           // Step 1: Do some processing and get a result
    
           this.executor.execute(() -> backgroundProcessResult());
    
           // Step 3: Further processing...
    
           // Step 4: Return back the API response
           return Response.ok().build();
        }
        
    

    But if you need to wait for the response of the background process, then you need to build a Mutiny pipeline, something like this:

    
        @GET
        @Path("test")   
        public Uni<Void> test() {
               return Uni.createFrom().item(() -> backgroundProcessResult())
                       .runSubscriptionOn(Infrastructure.getDefaultWorkerPool())
                       .map(result -> // doSomething with result)
                       .replaceWithVoid();
        }