I have a Spring Boot web application which shuts down gracefully after a timeout of 120secs.
Recently we have added a Spring Integration Flow to the same application to be able to process some files from a directory.
The poller uses a TaskExecutor to process files in multiple threads (5 for now).
public TaskExecutor chunkExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.setAwaitTerminationSeconds(120);
taskExecutor.setThreadNamePrefix("customExecutor-");
return taskExecutor;
}
PollerSpec looks like:
public void accept(SourcePollingChannelAdapterSpec sourcePollingChannelAdapterSpec) {
sourcePollingChannelAdapterSpec.poller(Pollers.fixedDelay(fixedDelay)
.taskExecutor(chunkExecutor)
.maxMessagesPerPoll(maxMessagesPerPoll)
.transactionSynchronizationFactory(transactionSyncFactory)
.transactional(new PseudoTransactionManager()));
}
We have noticed that the Spring Integration flow does not follow the graceful shutdown of the main application. In some instances, the poller even picks up files after the tomcat is shutdown.
If we don't use the taskExecutor, flow looks good
Is there anything else I need to do to make this Spring Integration flow shutdown gracefully like the main Spring Boot application while using the taskExecutor?
spring:
task:
scheduling:
thread-name-prefix: "customScheduling-"
pool:
size: 2
shutdown:
await-termination-period: "120s"
await-termination: true
PollerSpec:
public void accept(SourcePollingChannelAdapterSpec sourcePollingChannelAdapterSpec) {
sourcePollingChannelAdapterSpec.poller(Pollers.fixedDelay(fixedDelay)
//.taskExecutor(chunkExecutor)
.maxMessagesPerPoll(maxMessagesPerPoll)
.transactionSynchronizationFactory(transactionSyncFactory)
.transactional(new PseudoTransactionManager()));
}
From the logs I noticed that the tomcat has already shutdown while the scheduler is waiting for a REST call to complete.
Like Artem mentioned, the shutdown was really for the tomcat and not for the async tasks. I was able to have a graceful shutdown of the executor by implementing an EventListener
for onContextClosedEvent
and call the shutDown
on the taskExecutor
. This invokes the graceful shutdown of the taskExecutor
@EventListener
public void onContextClosedEvent(ContextClosedEvent event) {
taskExecutor.shutdown();
}