Open okohub opened 3 days ago
It wasn't really a decision that was made in Spring Boot as both SimpleAsyncTaskExecutor
and ThreadPoolTaskExecutor
are provided by Spring Framework.
The javadoc for SimpleAsyncTaskExecutor
notes its current behavior where it says that it "does not participate in a coordinated lifecycle stop but rather just awaits task termination on close()
. Based on my current understanding, I don't think we'd want to override this design decision in Boot as participation in the lifecycle process isn't something that's unique to Boot.
We'll transfer this issue to the Framework team in the first instance for their consideration.
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!