From 6791ea94a0c5101ce31fcbd4b1f581e311388d75 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 16 Feb 2024 14:16:32 +0100 Subject: [PATCH] Change executor phase to MAX_VALUE/2 and reduce timeout to 10 seconds Closes gh-32152 --- .../context/SmartLifecycle.java | 5 ++++- .../support/DefaultLifecycleProcessor.java | 4 ++-- .../ExecutorConfigurationSupport.java | 18 +++++++++++++++++- .../concurrent/SimpleAsyncTaskScheduler.java | 10 +++++++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java b/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java index 5ad500d1b211..7567e0f4982c 100644 --- a/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java +++ b/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java @@ -72,9 +72,12 @@ public interface SmartLifecycle extends Lifecycle, Phased { * {@link Lifecycle} implementations, putting the typically auto-started * {@code SmartLifecycle} beans into a later startup phase and an earlier * shutdown phase. + *

Note that certain {@code SmartLifecycle} components come with a different + * default phase: e.g. executors/schedulers with {@code Integer.MAX_VALUE / 2}. * @since 5.1 * @see #getPhase() - * @see org.springframework.context.support.DefaultLifecycleProcessor#getPhase(Lifecycle) + * @see org.springframework.scheduling.concurrent.ExecutorConfigurationSupport#DEFAULT_PHASE + * @see org.springframework.context.support.DefaultLifecycleProcessor#setTimeoutPerShutdownPhase */ int DEFAULT_PHASE = Integer.MAX_VALUE; diff --git a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java index 91b486de53f3..43e4c52926b2 100644 --- a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java @@ -106,7 +106,7 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor private final Log logger = LogFactory.getLog(getClass()); - private volatile long timeoutPerShutdownPhase = 30000; + private volatile long timeoutPerShutdownPhase = 10000; private volatile boolean running; @@ -135,7 +135,7 @@ else if (checkpointOnRefresh) { /** * Specify the maximum time allotted in milliseconds for the shutdown of any * phase (group of {@link SmartLifecycle} beans with the same 'phase' value). - *

The default value is 30000 milliseconds (30 seconds). + *

The default value is 10000 milliseconds (10 seconds) as of 6.2. * @see SmartLifecycle#getPhase() */ public void setTimeoutPerShutdownPhase(long timeoutPerShutdownPhase) { diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java index 5f20eb75aff7..2bb0c6666fac 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java @@ -33,6 +33,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; +import org.springframework.context.Lifecycle; import org.springframework.context.SmartLifecycle; import org.springframework.context.event.ContextClosedEvent; import org.springframework.lang.Nullable; @@ -58,6 +59,20 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean, SmartLifecycle, ApplicationListener { + /** + * The default phase for an executor {@link SmartLifecycle}: {@code Integer.MAX_VALUE / 2}. + *

This is different from the default phase {@code Integer.MAX_VALUE} associated with + * other {@link SmartLifecycle} implementations, putting the typically auto-started + * executor/scheduler beans into an earlier startup phase and a later shutdown phase while + * still leaving room for regular {@link Lifecycle} components with the common phase 0. + * @since 6.2 + * @see #getPhase() + * @see SmartLifecycle#DEFAULT_PHASE + * @see org.springframework.context.support.DefaultLifecycleProcessor#setTimeoutPerShutdownPhase + */ + public static final int DEFAULT_PHASE = Integer.MAX_VALUE / 2; + + protected final Log logger = LogFactory.getLog(getClass()); private ThreadFactory threadFactory = this; @@ -218,7 +233,8 @@ public void setAwaitTerminationMillis(long awaitTerminationMillis) { /** * Specify the lifecycle phase for pausing and resuming this executor. - * The default is {@link #DEFAULT_PHASE}. + *

The default for executors/schedulers is {@link #DEFAULT_PHASE} as of 6.2, + * for stopping after other {@link SmartLifecycle} implementations. * @since 6.1 * @see SmartLifecycle#getPhase() */ diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/SimpleAsyncTaskScheduler.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/SimpleAsyncTaskScheduler.java index 5be8c7df33d9..3b162ce97306 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/SimpleAsyncTaskScheduler.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/SimpleAsyncTaskScheduler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,14 @@ public class SimpleAsyncTaskScheduler extends SimpleAsyncTaskExecutor implements TaskScheduler, ApplicationContextAware, SmartLifecycle, ApplicationListener { + /** + * The default phase for an executor {@link SmartLifecycle}: {@code Integer.MAX_VALUE / 2}. + * @since 6.2 + * @see #getPhase() + * @see ExecutorConfigurationSupport#DEFAULT_PHASE + */ + public static final int DEFAULT_PHASE = ExecutorConfigurationSupport.DEFAULT_PHASE; + private static final TimeUnit NANO = TimeUnit.NANOSECONDS;