Skip to content

Graceful shutdown does not cancel @Scheduled tasks #32109

Closed
@MelvinFrohike

Description

@MelvinFrohike

Steps to reproduce:

  1. Create a minimal spring-boot 3.2.2 project
  2. Add @EnableScheduling to application
  3. Define a taskScheduler bean of type ThreadPoolTaskScheduler
  4. Create a method annotated with @Scheduled(fixedRate=1000)
  5. Have a long running process in that method
  6. In application.properties set server.shutdown=graceful and spring.lifecycle.timeout-per-shutdown-phase=5s

If I understand the docs correctly, the long running process should be canceled immediately and the task scheduler should be destroyed.

However, when signaling the application to shutdown, the long running process is not aborted immediately. Instead, I get an error message after 5 seconds: Failed to shut down 1 bean with phase value 2147483647 within timeout of 5000ms: [taskScheduler]

If I configure the taskScheduler with

taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setAwaitTerminationMillis(0); 

the task is canceled immediately.

Minimal example

    @Bean
    public TaskScheduler taskScheduler() {
        var taskScheduler = new ThreadPoolTaskScheduler() {
            @Override
            public void destroy() {
                log.info("taskScheduler Destroy");
                super.destroy();
            }
        };
        taskScheduler.setPoolSize(10);
        taskScheduler.setWaitForTasksToCompleteOnShutdown(false); // this doesn't result in task cancelation.

//        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
//        taskScheduler.setAwaitTerminationMillis(0);  // this results result in immediate task cancelation
  
      return taskScheduler;
    }

    @Scheduled(fixedRate = 1000)
    public void scheduled() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @PreDestroy
    void predestroy() {
        log.info("predestroy");
    }

The TaskScheduler's destroy method and the predestroy() method are not called until after the 5 second timeout.
If I configure the taskScheduler with setWaitForTasksToCompleteOnShutdown(true) and taskScheduler.setAwaitTerminationMillis(0), these methods are called immediately.

Is there a misunderstanding on my part, an error in the docs, or a bug?

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: documentationA documentation task

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions