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 should ignore scheduled exceptions after shutdown (not termination) #33334

Closed
genuss opened this issue Aug 7, 2024 · 5 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: superseded An issue that has been superseded by another type: enhancement A general enhancement

Comments

@genuss
Copy link
Contributor

genuss commented Aug 7, 2024

Basically my issue is described in #32381. The implemented solution works in almost all cases, but I still experience TaskRejectedException logged as errors in the following case:

  • application context is stopping;
  • ContextClosedEvent is already published;
  • SimpleAsyncTaskScheduler#scheduledExecutor is shut down, but didn't yet terminated;
    I couldn't create a minimal reproducible example, but I'd like to show an excerpt from logs.
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [cheduling-19424] c.c.MyTaskBean          : Task working
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.b.a.ApplicationAvailabilityBean      : Application availability state ReadinessState changed from ACCEPTING_TRAFFIC to REFUSING_TRAFFIC
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [ionShutdownHook] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@28a2a3e7, started on Wed Aug 07 09:59:00 CEST 2024
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [cheduling-19425] c.c.MyTaskBean          : Task working
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [cheduling-19426] c.c.MyTaskBean          : Task working
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [cheduling-19427] c.c.MyTaskBean          : Task working
2024-08-07T09:59:05.977+02:00 DEBUG 65937 --- [cheduling-19428] c.c.MyTaskBean          : Task working
2024-08-07T09:59:05.977+02:00 ERROR 65937 --- [cheduling-19428] o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task

org.springframework.core.task.TaskRejectedException: ExecutorService in shutdown state did not accept task: com.company.MyTaskBean$$Lambda/0x000003ff01a10ed0@3c00151f
	at org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler.schedule(SimpleAsyncTaskScheduler.java:234)
	at com.company.MyTaskBean.task(MyTaskBean.kt:87)
	at com.company.MyTaskBean.task$lambda$1(MyTaskBean.kt:87)
	at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
	at java.base/java.lang.VirtualThread.run(VirtualThread.java:329)
Caused by: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask@93d3468[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@74f27d38[Wrapped task = org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler$$Lambda/0x000003ff019a8f70@53630565]] rejected from org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler$1@1d884a19[Shutting down, pool size = 1, active threads = 0, queued tasks = 2, completed tasks = 19427]
	at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2081)
	at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:841)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:340)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:562)
	at org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler.schedule(SimpleAsyncTaskScheduler.java:231)
	... 4 common frames omitted

2024-08-07T09:59:05.978+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147483647
2024-08-07T09:59:05.978+02:00 TRACE 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Asking bean 'taskScheduler' of type [org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler] to stop
2024-08-07T09:59:05.978+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Bean 'taskScheduler' completed its stop procedure
2024-08-07T09:59:05.978+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147482623
2024-08-07T09:59:05.978+02:00 TRACE 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Asking bean 'webServerGracefulShutdown' of type [org.springframework.boot.web.context.WebServerGracefulShutdownLifecycle] to stop
2024-08-07T09:59:05.979+02:00  INFO 65937 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2024-08-07T09:59:05.980+02:00  INFO 65937 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete
2024-08-07T09:59:05.980+02:00 DEBUG 65937 --- [tomcat-shutdown] o.s.c.support.DefaultLifecycleProcessor  : Bean 'webServerGracefulShutdown' completed its stop procedure
2024-08-07T09:59:05.981+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147481599
2024-08-07T09:59:05.981+02:00 TRACE 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Asking bean 'webServerStartStop' of type [org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle] to stop
2024-08-07T09:59:05.981+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Bean 'webServerStartStop' completed its stop procedure
2024-08-07T09:59:05.981+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase -2147483647
2024-08-07T09:59:05.981+02:00 TRACE 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Asking bean 'springBootLoggingLifecycle' of type [org.springframework.boot.context.logging.LoggingApplicationListener$Lifecycle] to stop
2024-08-07T09:59:05.981+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Bean 'springBootLoggingLifecycle' completed its stop procedure
2024-08-07T09:59:05.982+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService
2024-08-07T09:59:05.985+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
2024-08-07T09:59:05.985+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans
2024-08-07T09:59:05.986+02:00  INFO 65937 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : read-only - Shutdown initiated...
2024-08-07T09:59:05.988+02:00  INFO 65937 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : read-only - Shutdown completed.
2024-08-07T09:59:05.988+02:00  INFO 65937 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : read-write - Shutdown initiated...
2024-08-07T09:59:05.989+02:00  INFO 65937 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : read-write - Shutdown completed.
2024-08-07T09:59:05.989+02:00 DEBUG 65937 --- [ionShutdownHook] o.s.b.f.support.DisposableBeanAdapter    : Custom destroy method 'close' on bean with name 'simpleclientPrometheusMeterRegistry' completed

I suppose, the reason can be explained as follows.

  • SimpleAsyncTaskScheduler#onApplicationEvent calls ExecutorService#shutdown thus switching its running state to SHUTDOWN.
  • SimpleAsyncTaskScheduler#shutdownAwareErrorHandler checks for ExecutorService#isTerminated which only returns true if an executor is in TERMINATED running state.

The proposed solution: use ExecutorService#isShutdown instead.

I hesitated to create a PR as I also found a call to isTerminated to ExecutorLifecycleDelegate and not sure if it should be changed too.

@genuss genuss changed the title SimpleAsyncTaskScheduler should ignore scheduled exceptions after shutdown SimpleAsyncTaskScheduler should ignore scheduled exceptions after shutdown (not termination) Aug 7, 2024
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Aug 7, 2024
@simonbasle simonbasle self-assigned this Aug 7, 2024
@simonbasle simonbasle added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Aug 7, 2024
@simonbasle simonbasle added this to the 6.2.0-M7 milestone Aug 7, 2024
@simonbasle
Copy link
Contributor

Thanks for the detailed analysis @genuss. I think what you propose for SimpleAsyncTaskScheduler#shutdownAwareErrorHandler makes sense. The ExecutorLifecycleDelegate should be reviewed separately though.

@genuss
Copy link
Contributor Author

genuss commented Aug 7, 2024

Should I create a PR for the change?

@simonbasle
Copy link
Contributor

@genuss if you have something ready, please go ahead :)

@jhoeller
Copy link
Contributor

jhoeller commented Aug 7, 2024

Sounds sensible to use isShutdown() there, suppressing the log entry even before full termination there.

As for ExecutorLifecycleDelegate, the use of isTerminated() seems correct there since isRunning() is expected to return true up until actual termination.

@jhoeller jhoeller added the in: core Issues in core modules (aop, beans, core, context, expression) label Aug 7, 2024
@jhoeller
Copy link
Contributor

jhoeller commented Aug 7, 2024

Superseded by PR #33336.

@jhoeller jhoeller closed this as not planned Won't fix, can't repro, duplicate, stale Aug 7, 2024
@jhoeller jhoeller added the status: superseded An issue that has been superseded by another label Aug 7, 2024
@jhoeller jhoeller removed this from the 6.2.0-M7 milestone Aug 7, 2024
simonbasle pushed a commit that referenced this issue Aug 7, 2024
This changes the criteria for simplified task rejection logging from
to be that the executor is in the shutdown phase, not fully terminated.

See gh-33334
Closes gh-33336
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) status: superseded An issue that has been superseded by another type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants