Spring Boot Async method in controller is executing synchronously
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When a Spring Boot controller method marked async still behaves synchronously, the cause is usually proxying or thread configuration, not the annotation itself. @Async works through Spring proxies, so self-invocation, missing @EnableAsync, or wrong return types can make code run on request thread. A reliable async setup requires correct bean boundaries, executor configuration, and observable thread behavior.
Core Sections
1. Enable async support
Without @EnableAsync, @Async annotations are ignored.
2. Use async method on separate bean
Controller:
Self-calls inside same bean bypass proxy and stay synchronous.
3. Configure dedicated executor
Thread naming helps confirm offloaded execution.
4. Return types and behavior
Preferred async signatures include CompletableFuture<T>, ListenableFuture<T>, or void (with caveats). Returning plain T from controller often implies synchronous completion path.
5. Observe thread execution
Log thread name in async method:
If you still see request thread names, proxy/executor setup is wrong.
6. Consider reactive alternative
For IO-heavy APIs, Spring WebFlux/reactive stacks may provide better end-to-end non-blocking semantics than ad hoc @Async usage.
Validation and production readiness
A practical implementation should be validated beyond the happy path. Create a compact test matrix that includes standard input, boundary conditions, invalid data, and one realistic production-sized case. This reveals issues that unit-level examples often miss, such as silent coercions, ordering assumptions, and timeout behavior under load. If the workflow includes file or network operations, include at least one fault-injection test that simulates missing resources and transient failures.
Operational safeguards are equally important. Add structured logging around the critical branches so you can diagnose failures quickly without reproducing them from scratch. A good log record should include operation name, key identifiers, and final outcome. Keep sensitive values masked. For asynchronous or background flows, include correlation IDs so related events can be traced across threads and services.
Define explicit fallback behavior before incidents occur. Decide whether the code should retry, fail fast, or degrade gracefully when dependencies are unavailable. If retries are used, bound them and use backoff. Unbounded retries often hide real outages and can amplify load problems. Add monitoring counters for success/failure/latency so regressions become visible immediately after deployment.
Finally, keep a short runbook near the code or documentation: required runtime versions, known platform differences, and a rollback plan. This turns one-off fixes into repeatable operational practices. Teams that standardize these checks usually reduce debugging time and avoid recurring reliability bugs.
Common Pitfalls
- Missing
@EnableAsyncin configuration. - Calling
@Asyncmethod from within same class (self-invocation). - Using synchronous return types and expecting async behavior.
- Not configuring executor capacity for real workload.
- Assuming async annotation alone solves blocking downstream IO.
Summary
If @Async controller flows run synchronously, verify proxy boundaries, enable async support, and configure a real executor. Keep async methods in separate beans and return proper future types. Confirm behavior via thread-name logs to ensure execution truly leaves request thread.
Teams that document this exact approach in shared guidelines and enforce it through CI checks reduce repeated regressions, accelerate onboarding, and keep behavior consistent across local development, automated pipelines, and production operations.
Related reading
- Spring Boot Async method not running in separate Thread
- Spring Cancel Async Task
- Spring Kafka asynchronous send calls block
- Spring Kafka is Acknowledgement.acknowledge thread safe?
- Spring Boot Authentication for Integration Tests
- Spring Boot auto configuration for datasource
- spring kafka thorws InstanceAlreadyExistsException exception after setting concurrency > 1
- Spring @KafkaListener and concurrency

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack 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.