-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent Lifecycle Management with Virtual Threads in Spring Boot Async Configuration #33780
Comments
It wasn't really a decision that was made in Spring Boot as both The javadoc for We'll transfer this issue to the Framework team in the first instance for their consideration. |
This is fundamentally by design: Even That said, if tight management of execution threads and deep integration with context-level lifecycle management is necessary, you'll be better off with the traditional I'm going to use this issue for documenting the intended lifecycle behavior of |
@jhoeller thank you 👍 |
@okohub We have a question regarding your application setup (that's in the context of spring-projects/spring-boot#42921). It seems that with the Can you tell us more about the components submitting tasks and whether tasks themselves are lifecycle-aware? I theory, if those are lifecycle-aware they should stop submitting new tasks during the graceful shutdown phase and this should be less of a problem. Thanks! |
@bclozel Flow is simple, in practice, there is an API (controller method) that calls a service method wrapped with "Async" annotation. This AsyncInterceptor based task/call is not lifecycle-aware as far as I see. Service method (task/call) starts sending kafka messages asynchronously. Imagine like that:. // controller
@PostMapping("/do")
public void doSomething() {
service.sendAsync();
}
// service
@Async
@Override
public void sendAsync() {
//some call here
} When context is closing, or graceful shutdown in progress, if "some call here" parts are closing before refusing new requests, problem occurs. I hope it helps. |
Spring Boot’s graceful shutdown process relies on Lifecycle beans to ensure safe startup and shutdown sequences. These beans are invoked in a prioritized order, starting with the highest priority during startup and stopping in reverse order during shutdown.
Let’s review two key configurations: Task Scheduling and Task Execution.
The configuration for task scheduling in org.springframework.boot.autoconfigure.task.TaskSchedulingConfigurations.TaskSchedulerConfiguration is as follows:
Both SimpleAsyncTaskScheduler and ThreadPoolTaskScheduler implement SmartLifecycle, ensuring they follow the graceful shutdown process. This works as expected.
The configuration for async execution in org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations.TaskExecutorConfiguration is:
Here, the ThreadPoolTaskExecutor (used for platform threads) implements SmartLifecycle, but the SimpleAsyncTaskExecutor (used for virtual threads) does not. This creates a problem during graceful shutdowns when using virtual threads.
The Problem:
In cases where a task is interacting with external services (e.g., producing messages to Kafka), the use of SimpleAsyncTaskExecutor without lifecycle awareness can lead to premature shutdown of dependent beans (e.g., Kafka producers) before the task completes. This may cause exceptions or incomplete task execution.
Proposed Solution:
To resolve this, I implemented a custom LifecycleAwareAsyncTaskExecutor that ensures tasks complete gracefully before shutting down, even with virtual threads:
Was it an intentional design decision in Spring Boot to skip lifecycle management for virtual thread executors? Or is this an opportunity for improvement to ensure graceful shutdown for virtual thread-based executors as well?
Thanks!
The text was updated successfully, but these errors were encountered: