Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing Asynchronous Rest API using Spring boot and CompletableFuture and its thread management

I have a question about thread management for the tomcat server and application. Here is a sample code:

@RequestMapping(path = "/asyncCompletable", method = RequestMethod.GET)
    public CompletableFuture<String> getValueAsyncUsingCompletableFuture() {

        logger.info("Request received");
        CompletableFuture<String> completableFuture
                = CompletableFuture.supplyAsync(this::processRequest);
        logger.info("Servlet thread released");
        return completableFuture;

    }

    private String processRequest() {
        Long delayTime = 10000L;
        logger.info("Start processing request");
        try {
            Thread.sleep(delayTime);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        logger.info("Completed processing request");
        return "Processing done after " + delayTime;
    }

Here, This is a simple API using spring boot. What I have done here?

  • It is simple endpoints that is a simple GET method and returning a string as a response.
  • In method getValueAsyncUsingCompletableFuture I am calling processRequest on CompletableFuture.supplyAsync(this::processRequest). So obviously it will run under separate thread.
  • In method processRequest where only have a Thread.sleep for 10s.
  • Both methods have an entry and exit log.
  • Also the API getValueAsyncUsingCompletableFuture is returning a completableFuture

Now after calling the Endpoints from the browser its output is as expected. It waits 10 seconds and provides a response. The output log is given below. enter image description here

Here, 

  • The first and second line of log is showing under nio-8080-exec-8 thread. It also showing request received and servlet thread released.
  • In the last 2 lines of log for method processRequest. Here it is showing for CompletableFuture execution part. It is handling under onPool-worker-2 thread.

Now, Here is my question:

  1. During the execution of processRequest method, is it released the tomcat allocated thread nio-8080-exec-8? I am telling based on the log. Is this thread released and go back to tomcat connection pool?
  2. If the tomcat thread released then how the client is getting a response after the execution of completableFuture is done?
  3. Can you please describe how thread allocation occur when request come to tomcat server, and spring application.

Thanks in advance

like image 358
Md. Sajedul Karim Avatar asked Oct 24 '25 05:10

Md. Sajedul Karim


1 Answers

Spring uses the ServletRequest#startAsync() method introduced in Servlet 3.0 (see Oracle's tutorial). This means that:

  1. The Tomcat thread http-nio-8080-exec-8 is returned to its executor shortly after getValueAsyncUsingCompletableFuture is called, but the response is not yet committed to the client as in the synchronous case. Spring switches the ServletRequest into asynchronous mode whenever your handler returns a CompletionStage.
  2. After your method getValueAsyncUsingCompletableFuture exits, the ServletRequest and ServletResponse can still be used to send data to the client. Spring appends a stage to your CompletableFuture, which writes the result to ServletResponse and ends the request using AsyncContext#complete(). This stage can be executed on any thread. In your case it executes on the ForkJoinPool since you launched the CompletableFuture using the default executor. However any executor would be fine.
  3. Tomcat allocates a thread to execute getValueAsyncUsingCompletableFuture (or more precisely DispatcherServlet#service). The rest of the allocations is up to you.
like image 184
Piotr P. Karwasz Avatar answered Oct 25 '25 19:10

Piotr P. Karwasz