Description
Currently, ExecutorConfigurationSupport#shutdown()
encapsulate multiple scenarios for shutting down internal ExecutorService
.
The single method shutdown()
performs shutdown()/shutdownNow()
(non-blocking) and awaitTermination()
(blocking) based on its property.
I am writing a graceful shutdown logic for task executor/scheduler.
The logic for graceful shutdown is to retrieve all task executor/schedulers and apply:
- Call
shutdown()
to not accept anymore tasks - Wait currently running task for the duration of graceful period
With current available API, I need to do following:
Instant deadline = start.plus(gracefulShutdownTimeout);
// stop receiving anymore request while keep running active ones
for (ExecutorConfigurationSupport executorConfigurationSupport : this.executorConfigurationSupports) {
executorConfigurationSupport.setWaitForTasksToCompleteOnShutdown(true);
executorConfigurationSupport.shutdown(); // non-blocking
}
// Previously, executors are called "shutdown()"; so, no more new tasks are scheduled.
// Now, call "awaitTermination()" to wait current tasks to finish while
// the container is shutting down in parallel.
for (ExecutorConfigurationSupport executorConfigurationSupport : this.executorConfigurationSupports) {
int awaitTerminationSeconds = Math.toIntExact(Duration.between(Instant.now(), deadline).getSeconds());
executorConfigurationSupport.setAwaitTerminationSeconds(awaitTerminationSeconds);
executorConfigurationSupport.shutdown(); // blocking
}
Since this calls shutdown()
twice with different parameter in order to achieve shutdown()
and awaitTermination()
for underlying executor, it is not so intuitive. Also requires to know the detail about what ExecutorConfigurationSupport#shutdown()
does.
Another workaround is to retrieve internal ExecutorService
and call shutdown()
and awaitTermination()
.
List<ExecutorService> executorServices = new ArrayList<>();
for (ExecutorConfigurationSupport executorConfigurationSupport : this.executorConfigurationSupports) {
if (executorConfigurationSupport instanceof ThreadPoolTaskExecutor) {
executorServices.add(((ThreadPoolTaskExecutor)executorConfigurationSupport).getThreadPoolExecutor());
}
else if (executorConfigurationSupport instanceof ThreadPoolTaskScheduler) {
executorServices.add(((ThreadPoolTaskScheduler)executorConfigurationSupport).getScheduledExecutor());
}
}
for(ExecutorService executorService : executorServices) {
executorService.shutdown();
}
for(ExecutorService executorService : executorServices) {
executorService.awaitTermination(...);
}
I think it would be nice to have some API refinement for task executor/scheduler to easily control underlying ExecutorService
.
Simple solution is to to add a getter to ExecutorConfigurationSupport
to expose internal ExecutorService
. This way, in addition to existing shutdown()
, if user needs to do more fine control on shutdown, getter can expose the ExecutorService
.
Another way is to provide blocking(awaitTermination
) and non-blocking(shutdown/shutdownNow
) methods on ExecutorConfigurationSupport
instead or in addition to the current shutdown()
method.