Skip to content
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

SimpleAsyncTaskScheduler: task with fixed delay stops working after unhandled exception #31749

Closed
ztomic opened this issue Dec 4, 2023 · 8 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Milestone

Comments

@ztomic
Copy link

ztomic commented Dec 4, 2023

When using virtual threads all @Scheduled executors stop working after first exception on any @Scheduled executor and no error is logged. With disabled virtual threads @Scheduled executors continue working and exception is logged with TaskUtils$LoggingErrorHandler and SimpleAsyncUncaughtExceptionHandler.

Demo is here: https://github.com/ztomic/scheduling-demo

In this demo DemoEvent is generated every 5 seconds with @Scheduled task, and there are two listeners, one is @Async and other is synchronous and both of them are throwing exception on every second invocation. Also, there is one @Scheduled task which throws exception on every second invocation.

With disabled virtual threads, all @Scheduled tasks continue working after exception.

Run application with virtual threads disabled and after that with virtual threads enabled in application.yml.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Dec 4, 2023
@wilkinsona wilkinsona self-assigned this Dec 4, 2023
@philwebb philwebb changed the title Spring Boot 3.2 @Scheduled task stop working after unhandled exception when virtual threads are enabled Spring Boot 3.2 @Scheduled task stop working after unhandled exception when virtual threads are enabled Dec 4, 2023
@ztomic
Copy link
Author

ztomic commented Dec 4, 2023

Also ThreadPoolTaskSchedulerCustomizer is not used with virtual threads.

@Bean
	public ThreadPoolTaskSchedulerCustomizer threadPoolTaskSchedulerCustomizer() {
		return taskScheduler -> {
			taskScheduler.setErrorHandler(t -> LoggerFactory.getLogger(ThreadPoolTaskScheduler.class).error("Unexpected error occurred in {}scheduled task.", Thread.currentThread().isVirtual() ? "virtual " : "", t));
		};
	}

@wilkinsona
Copy link
Member

wilkinsona commented Dec 4, 2023

When using virtual threads all @Scheduled executors stop working after first exception on any @Scheduled executor and no error is logged. With disabled virtual threads @Scheduled executors continue working and exception is logged with TaskUtils$LoggingErrorHandler and SimpleAsyncUncaughtExceptionHandler

Thanks for the report and sample project. The difference in behaviour is due to differences in Spring Framework's ThreadPoolTaskScheduler (used with platform threads) and SimpleAsyncTaskScheduler (used with virtual threads). The latter does not have an ErrorHandler and therefore does not decorate the scheduled tasks with the error handler.

I don't think there's anything we can do about this in Spring Boot as there's no way that I am aware of for us to combine the simple non-pooling behaviour of SimpleAsyncTaskScheduler with the error handling behaviour of ThreadPoolTaskScheduler. We'll transfer this issue to the Framework team for their consideration.

ThreadPoolTaskSchedulerCustomizer is not used with virtual threads

This is to be expected as there's no ThreadPoolTaskScheduler and no pooling in general when using virtual threads.

@wilkinsona wilkinsona removed their assignment Dec 4, 2023
@mhalbritter
Copy link
Contributor

mhalbritter commented Dec 4, 2023

Also ThreadPoolTaskSchedulerCustomizer is not used with virtual threads.

If you use virtual threads, SimpleAsyncTaskScheduler is doing the scheduling. You can customize the scheduler with SimpleAsyncTaskSchedulerCustomizer.

If you use platform threads, ThreadPoolTaskScheduler is doing the scheduling. You can customize the scheduler with ThreadPoolTaskSchedulerCustomizer.

@bclozel bclozel transferred this issue from spring-projects/spring-boot Dec 4, 2023
@ztomic
Copy link
Author

ztomic commented Dec 4, 2023

Ok, thanks for clarifications. Maybe it should be mentioned in release notes or documentation (if not already), so users are aware that if they enable virtual threads they should also handle all exceptions in @Async and @Scheduled methods to avoid this behaviour.

@jhoeller jhoeller changed the title Spring Boot 3.2 @Scheduled task stop working after unhandled exception when virtual threads are enabled SimpleAsyncTaskScheduler: task with fixed delay stops working after unhandled exception Dec 4, 2023
@jhoeller jhoeller added type: bug A general bug in: core Issues in core modules (aop, beans, core, context, expression) and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Dec 4, 2023
@jhoeller jhoeller self-assigned this Dec 4, 2023
@jhoeller jhoeller added this to the 6.1.2 milestone Dec 4, 2023
@jhoeller
Copy link
Contributor

jhoeller commented Dec 4, 2023

I suppose this problem specifically materializes with fixed-delay tasks which we need to execute on the main scheduler thread... and which we therefore need to wrap in a defensive error handler.

@ztomic
Copy link
Author

ztomic commented Dec 5, 2023

I have tested with 6.1.2-SNAPSHOT and it seems that now is working ok.

@jhoeller
Copy link
Contributor

jhoeller commented Dec 6, 2023

Good to hear! Thanks for testing the snapshot.

@kSzajo
Copy link

kSzajo commented Apr 4, 2024

Also ThreadPoolTaskSchedulerCustomizer is not used with virtual threads.

If you use virtual threads, SimpleAsyncTaskScheduler is doing the scheduling. You can customize the scheduler with SimpleAsyncTaskSchedulerCustomizer.

If you use platform threads, ThreadPoolTaskScheduler is doing the scheduling. You can customize the scheduler with ThreadPoolTaskSchedulerCustomizer.

ThreadPoolTaskSchedulerCustomizerdoes not contain setErrorHandler

Is it possible to declare exception handler for SimpleAsyncTaskScheduler?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

6 participants