Spring
execution time
controller
method
timeout

Timing out the execution time of a controller/method in Spring

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Timing out a Spring controller method is trickier than it first sounds, because there are at least two different goals. Sometimes you want the HTTP request to stop waiting and return a timeout response. Other times you want the underlying work itself to be cancelled.

Those are not the same thing. A web timeout may end the request while the background work keeps running unless you design cancellation deliberately.

Timeout at the Web Layer With WebAsyncTask

In Spring MVC, a common way to apply request-level timeout behavior is to return a WebAsyncTask.

java
1import org.springframework.web.context.request.async.WebAsyncTask;
2import org.springframework.web.bind.annotation.GetMapping;
3import org.springframework.web.bind.annotation.RestController;
4
5@RestController
6public class ReportController {
7
8    @GetMapping("/report")
9    public WebAsyncTask<String> report() {
10        WebAsyncTask<String> task = new WebAsyncTask<>(2000L, () -> {
11            Thread.sleep(5000);
12            return "done";
13        });
14
15        task.onTimeout(() -> "request timed out");
16        return task;
17    }
18}

This tells Spring MVC to give up waiting after two seconds and return the timeout result.

That solves the HTTP response problem. It does not automatically guarantee that deeper work such as database calls or remote requests have stopped.

Using CompletableFuture With Timeout

If the controller delegates to async code, you can enforce timeout behavior at the future level.

java
1import java.util.concurrent.CompletableFuture;
2import java.util.concurrent.TimeUnit;
3import org.springframework.web.bind.annotation.GetMapping;
4import org.springframework.web.bind.annotation.RestController;
5
6@RestController
7public class JobController {
8
9    @GetMapping("/job")
10    public CompletableFuture<String> job() {
11        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
12            try {
13                Thread.sleep(5000);
14            } catch (InterruptedException e) {
15                Thread.currentThread().interrupt();
16            }
17            return "finished";
18        });
19
20        return future.orTimeout(2, TimeUnit.SECONDS)
21            .exceptionally(ex -> "timed out");
22    }
23}

This is useful when your controller already works with async flows. But again, it is important to understand whether the underlying work is truly interruptible.

Global MVC Async Timeout

If you want a global timeout for asynchronous MVC requests, configure it centrally:

java
1import org.springframework.context.annotation.Configuration;
2import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
3import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4
5@Configuration
6public class WebConfig implements WebMvcConfigurer {
7    @Override
8    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
9        configurer.setDefaultTimeout(3000);
10    }
11}

This applies to asynchronous request handling rather than to every blocking controller method automatically.

Timeout the Real Dependency, Not Just the Controller

Very often the controller is not the real problem. The real problem is a slow downstream dependency:

  • HTTP client call
  • database query
  • message broker request
  • external service

In those cases, the best timeout is usually at the client boundary. For example, set timeouts on WebClient, RestTemplate, the JDBC driver, or the HTTP client itself.

That is usually more reliable than trying to treat the controller as a magical kill switch for all deeper work.

Example With Service-Level Timeout

You can also push timeout behavior into a service layer using Future.get(timeout) style logic or a resilience library.

java
1import java.util.concurrent.*;
2
3public class SlowService {
4    private final ExecutorService executor = Executors.newCachedThreadPool();
5
6    public String runWithTimeout() throws Exception {
7        Future<String> future = executor.submit(() -> {
8            Thread.sleep(5000);
9            return "finished";
10        });
11
12        return future.get(2, TimeUnit.SECONDS);
13    }
14}

This makes the timeout rule reusable outside the controller, which is often a better design.

Request Timeout Versus Cancellation

This is the core distinction:

  • request timeout means the client stops waiting
  • cancellation means the underlying work actually stops

Cancellation only works if the code underneath supports interruption or cooperative cancellation. For example, a blocking library call that ignores interruption may continue running even after the HTTP layer already returned a timeout.

So if you truly need cancellation, design the work units and dependencies with that requirement explicitly.

When Resilience Libraries Help

For production systems, resilience libraries such as Resilience4j often provide a cleaner approach than hand-rolled timeout logic. They allow timeout policies, fallbacks, and monitoring around service calls instead of scattering timeout code across controllers.

That is especially useful when the timeout policy belongs to a downstream integration rather than to the HTTP endpoint itself.

Common Pitfalls

One common mistake is thinking a controller timeout automatically kills the underlying task. Often it only ends the HTTP wait.

Another mistake is timing out only at the controller while leaving downstream HTTP clients or database calls with no timeout at all.

It is also easy to use async timeout mechanisms without configuring a proper executor, which leads to misleading behavior under load.

Finally, timeout handling should return a useful error response or fallback. A raw stack trace or silent hanging thread is not an operational strategy.

Summary

  • In Spring, timing out a controller can mean timing out the HTTP response or cancelling the underlying work.
  • 'WebAsyncTask is a common MVC solution for request-level timeout handling.'
  • 'CompletableFuture.orTimeout works well for async flows.'
  • The best timeout often belongs at the slow dependency boundary, not only at the controller.
  • If true cancellation matters, make sure the underlying work is actually interruptible.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.