-
Notifications
You must be signed in to change notification settings - Fork 40.9k
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
When virtual threads are enabled, auto-configure an AsyncTaskExecutor that uses them #35710
Comments
Hello, is this issue available for work? If so, I would like to ask if there is a specific way to check for virtual threads availability in spring-boot. Thanks. |
@wilkinsona The default You would then be able to take advantage of other functionality related to the POC main...NicklasWallgren:spring-boot:35710-virtual-threads-thread-pool-task-executor |
Thanks for suggestion but I don't think that's the right approach. The JEP has a section that explicitly states that virtual threads should not be pooled. As such, I think it would be confusing for Boot's default configuration when virtual threads are enabled to use a If you believe that |
Alright, seems reasonable. Thanks! |
I've tested virtual threads support in 3.2.0-M1 and missing support for TaskScheduler. No issue was found for virtual threads in scheduling either. Is it planned to use virtual threads for scheduled tasks? |
Currently, I've used this bean definition as a workaround for task scheduling: bean<ConcurrentTaskScheduler>(name = "taskScheduler", isLazyInit = true) {
ConcurrentTaskScheduler(Executors.newScheduledThreadPool(0, Thread.ofVirtual().factory()))
}
|
As described in the JEP, virtual threads should not be pooled so we don't think it makes sense to use them for task scheduling. Advice/commentary from the Framework team:
|
Yes, I know - it is just a workaround for now. I can't find a suitable So my question: Is it planned to use virtual threads for scheduled tasks? (virtual threads-compatible Thank you! |
No. As I said above, the Framework team believe that using a single fairly scheduled platform thread is the best option. If you disagree with that and think that a virtual thread based implementation of |
It seems I missing something... How async and the scheduled task is different in the sense of execution? Why async task is executed on the virtual thread but the scheduled is not? What I expect is execution of scheduled tasks on virtual threads when |
The fundamental difference is that, by default, async execution is performed using multiple threads and scheduled task execution is performed using a single thread. As such, async execution lends itself well to the use of virtual threads – the pool of multiple platform threads can be replaced with unpooled virtual threads – but scheduled task execution does not. There's little point in replacing a single fairly scheduled platform thread with a single virtual thread. |
Thank you for such detailed explanation! So difference in default concurrency of scheduled tasks. Unfortunately I have no projects for 17 years with scheduler concurrency = 1. And no such defaults either (Quartz, JEE, Quarkus, Micronaut etc) I've try to file issue and provide PR against Framework. Thanks again |
@vladimirfx while a ticket in the Spring Framework issue tracker would be appreciated, I don't see us implementing and maintaining a totally custom That said, a common arrangement considered for such scenarios is a In order to avoid such an |
As a side note, is I'm wondering which configuration options we actually need for a virtual thread based Generally speaking, our preference is still an |
Exactly this variant I prototyping now. With configurable concurrency level (implemented though semaphore). I even preserve default concurrency = 1 😉 1 virtual thread for scheduling is better that one platform because most of time such a thread is waiting. Waiting virtual thread is way chipper than platform thread.
0 indicating that no thread cache is needed. Yes, 1 is more appropriate but changes nothing in semantic. Thank you for pointing to shutdown semantic differences - I've try to overcome it. |
On a related note, I'm about to introduce a Which still leaves room for a more pool-like virtual thread based scheduler. So if you are working on a custom implementation there, how does it effectively differ from a Last but not least, there is the question of what's a good default scheduler setup for Boot's virtual threads property. There is always the option of providing a custom executor/scheduler instead... however, the default choice is hard in its own right. |
@jhoeller How would one go about implementing graceful shutdown while using virtual threads in Spring Boot? It seem as neither Sorry if I'm missing something obvious. |
General executors do not necessarily need to support lifecycle integration as long the submitters of the tasks are in control of the submitted tasks, setting active or shutdown signals on them and waiting for them to complete on shutdown. This is the case e.g. for our JMS DefaultMessageListenerContainer and its asynchronous invokers, and it is typically also the case for Future-based submissions where the caller interacts with the task through the For a non-pooled executor, an executor-controlled shutdown of all tasks would only be possible by holding on to all active tasks within the executor, waiting for their completion that way. To some degree, this goes against the grain of virtual threads, or at least against their idiomatic usage. If such a controlled shutdown is desirable, possibly in conjunction with a concurrency limit as well, I would actually consider a In terms of lifecycle management, a scheduler is a bit of a different beast: Since it has a scheduler thread that keeps triggering periodic task executions, it absolutely needs to participate in a controlled shutdown and it should also participate in context-wide pause/resume steps where its triggers need to be suspended. The new As hinted at above, there is room for several strategies here. It's just that the default choice for a Boot setup is hard: For classic thread pools, it's the question of which pool limit to use depending on how many threads are typically blocked. For a virtual thread executor, it's the question of how important executor-controlled lifecycle management is for a given application. I would not be surprised if common practice will turn out to use thread pools with virtual threads as a compromise between those two. |
Great, thank you for the detailed explanation! |
On review, it looks straightforward to provide a |
I've looking for something similar. If we implement such tracking we effectively duplicate the functionality of ScheduledExecutorService. So how it will be better than this:
My tries to implement correct shutdown behavior led me to the conclusion that I reimplement the pooling scheduler from JRE... So do we need something new? Its nothing wrong in using a pooling scheduler with pool size 0. |
There is a graceful shutdown option in the form of a As for needing something new, from where I stand right now, I see those two options indeed: either |
What do you think about this variant (sorry for Kotlin): bean<ConcurrentTaskScheduler>(name = "taskScheduler", isLazyInit = true) {
val concurrencyLevel = env.getProperty<Int>("spring.task.scheduling.concurrency") ?: 1
val executor = ScheduledThreadPoolExecutor(1, Thread.ofVirtual().factory()).apply {
this.maximumPoolSize = concurrencyLevel
}
ConcurrentTaskScheduler(executor)
}
|
Setting the maximum pool size on a As a side note, |
Currently,
TaskExecutionAutoConfiguration
auto-configures aThreadPoolTaskExecutor
built usingTaskExecutorBuilder
. We should consider providing an option to auto-configure aSimpleAsyncTaskExecutor
that uses virtual threads instead. Following these changes in Framework,SimpleAsyncTaskExecutor
can be configured to use virtual threads by callingsetVirtualThreads(true)
.The text was updated successfully, but these errors were encountered: