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

Add a way to set executeExistingDelayedTasksAfterShutdown from ThreadPoolTaskScheduler #26719

Closed
tkgregory opened this issue Mar 24, 2021 · 1 comment
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@tkgregory
Copy link

tkgregory commented Mar 24, 2021

Observed behaviour

ThreadPoolTaskScheduler is used for methods annotated with @Scheduled.

In the example of a method which is to be run at a specific time e.g. @Scheduled( cron = "0 0 2 * * *" ) (run at 2 a.m.), the ScheduledThreadPoolExecutor within ThreadPoolTaskScheduler knows that it must execute this at the future time.

However, when I call threadPoolTaskScheduler.shutdown() the shutdown is being blocked until the queued task has been exectued. In the above example this would be, 2 a.m. + the time it takes to execute the task. Note that this behaviour only happens when I have configured a long enough termination period with threadPoolTaskScheduler.setAwaitTerminationSeconds.

One other point. I know the ThreadPoolTaskScheduler will get automatically shutdown when the application shuts down, but I am doing it manually for other reasons which I won't go into in this issue.

In summary:

  • I have a method scheduled for execution in the future
  • my ThreadPoolTaskScheduler has a long terimation period (setAwaitTerminationSeconds)
  • before that time I'm manually calling threadPoolTaskScheduler.shutdown()
  • shutdown is blocking until the scheduled time

My requirement here is that the ThreadPoolTaskScheduler should shut down faster by only waiting for those tasks which are currently being processed. Tasks which are scheduled for a future time will not be executed.

Current workaround

I found a method on ScheduledThreadPoolExecutor named setExecuteExistingDelayedTasksAfterShutdownPolicy which seems to do what I need.

* Sets the policy on whether to execute existing delayed
* tasks even when this executor has been {@code shutdown}.
* In this case, these tasks will only terminate upon
* {@code shutdownNow}, or after setting the policy to
* {@code false} when already shutdown.
* This value is by default {@code true}.

When I set this value to false by configuring a custom ThreadPoolTaskScheduler I observe the desired behaviour.

        final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler()
        {
            @Override
            protected ExecutorService initializeExecutor(final ThreadFactory threadFactory, final RejectedExecutionHandler rejectedExecutionHandler)
            {
                final ExecutorService executorService = super.initializeExecutor(threadFactory, rejectedExecutionHandler);

                if (executorService instanceof ScheduledThreadPoolExecutor)
                {
                    ((ScheduledThreadPoolExecutor) executorService).setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
                }

                return executorService;
            }
        };

Suggested improvement

Could we configure this more easily using a property on the ThreadPoolTaskScheduler? In the ThreadPoolTaskScheduler method initializeExecutor it already does similar configurations e.g. for the removeOnCancelPolicy

		if (this.removeOnCancelPolicy) {
			if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
				((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true);
			}
			else {
				logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
			}
		}

If being able to set this configuration would be valuable for this framework, then maybe this would be a suitable place to put it?

The end result of how to use the new functionality might look like this:

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler()
    {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
        return scheduler;
    }
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Mar 24, 2021
@jhoeller jhoeller self-assigned this Mar 24, 2021
@jhoeller jhoeller added in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Mar 24, 2021
@jhoeller jhoeller added this to the 5.3.6 milestone Mar 24, 2021
@jhoeller jhoeller modified the milestones: 5.3.6, 5.3.7 Apr 12, 2021
Aelykto pushed a commit to Aelykto/spring-framework that referenced this issue Apr 15, 2021
Aelykto pushed a commit to Aelykto/spring-framework that referenced this issue Apr 15, 2021
…Shutdown property. This closes an existing issue: spring-projects#26719"

This reverts commit f179d53
Aelykto pushed a commit to Aelykto/spring-framework that referenced this issue Apr 15, 2021
…nd ContinueExistingPeriodicTasksAfterShutdown policies. This closes an existing issue: spring-projects#26719"
Aelykto pushed a commit to Aelykto/spring-framework that referenced this issue Apr 16, 2021
…nd ContinueExistingPeriodicTasksAfterShutdown policies. This closes an existing issue: spring-projects#26719"
@jhoeller jhoeller modified the milestones: 5.3.7, 5.3.8 May 10, 2021
@jhoeller jhoeller modified the milestones: 5.3.8, 5.3.9 Jun 4, 2021
@jhoeller
Copy link
Contributor

I ended up introducing the remaining policy setter methods from ScheduledThreadPoolExecutor but without corresponding getters, along with deprecating the isRemoveOnCancelPolicy method. Such policy getters aren't really necessary during the configuration phase and can be called via getScheduledThreadPoolExecutor() at runtime.

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: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants