Spring 引导:通过控制涉及 MongoClient 的终止顺序正常关闭
Spring Boot: gracefully shutdown by controlling termination order involving MongoClient
我有一个 Spring 引导应用程序,它使用 AsyncTaskExecutor
(数字是预定义的)
产生许多线程
线程执行一个无限循环,从一些队列和进程对象中读取,所以我没有真正的拒绝策略机制(比如接受 tasks
的线程池)
问题是当应用程序关闭时,线程可能(并且很可能)忙于处理一个项目,该项目包括使用 MongoTemplate
对 Mongo 的操作。
因此,当应用程序关闭时,Mongo客户端会自动 close()
,然后我从 Mongo 收到一些错误,例如:
java.lang.IllegalStateException: The pool is closed
at com.mongodb.internal.connection.ConcurrentPool.get(ConcurrentPool.java:137)
at com.mongodb.internal.connection.DefaultConnectionPool.getPooledConnection(DefaultConnectionPool.java:262)
at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:103)
at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:92)
at com.mongodb.internal.connection.DefaultServer.getConnection(DefaultServer.java:85)
如何优雅地关闭应用程序?例如在不关闭 MongoClient 的情况下中断线程?
代码:
Bean 创建:
@Bean
AsyncTaskExecutor getTaskExecutor() {
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
return executor;
}
只需通过以下方式执行:
executor.execute(runnable);
不要使用 SimpleAsyncTaskExecutor
- SimpleAsyncTaskExecutor 为每个请求创建一个新线程而不是使用 ThreadPoolTaskExecutor
并配置下面提到的两个属性。
/**
* Set whether to wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* <p>Default is "false", shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
* prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Note that Spring's container shutdown continues while ongoing tasks
* are being completed. If you want this executor to block and wait for the
* termination of tasks before the rest of the container continues to shut
* down - e.g. in order to keep up other resources that your tasks may need -,
* set the {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"}
* property instead of or in addition to this property.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
/**
* Set the maximum number of seconds that this executor is supposed to block
* on shutdown in order to wait for remaining tasks to complete their execution
* before the rest of the container continues to shut down. This is particularly
* useful if your remaining tasks are likely to need access to other resources
* that are also managed by the container.
* <p>By default, this executor won't wait for the termination of tasks at all.
* It will either shut down immediately, interrupting ongoing tasks and clearing
* the remaining task queue - or, if the
* {@link #setWaitForTasksToCompleteOnShutdown "waitForTasksToCompleteOnShutdown"}
* flag has been set to {@code true}, it will continue to fully execute all
* ongoing tasks as well as all remaining tasks in the queue, in parallel to
* the rest of the container shutting down.
* <p>In either case, if you specify an await-termination period using this property,
* this executor will wait for the given time (max) for the termination of tasks.
* As a rule of thumb, specify a significantly higher timeout here if you set
* "waitForTasksToCompleteOnShutdown" to {@code true} at the same time,
* since all remaining tasks in the queue will still get executed - in contrast
* to the default shutdown behavior where it's just about waiting for currently
* executing tasks that aren't reacting to thread interruption.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#awaitTermination
*/
public void setAwaitTerminationSeconds(int awaitTerminationSeconds) {
this.awaitTerminationSeconds = awaitTerminationSeconds;
}
相关部分
Set the maximum number of seconds that this executor is supposed to
block on shutdown in order to wait for remaining tasks to complete
their execution before the rest of the container continues to shut
down. This is particularly useful if your remaining tasks are likely
to need access to other resources that are also managed by the
container.
您可以使用 spring 自动配置来配置以控制任务执行属性(首选)或使用 @Bean
注释
以编程方式进行配置
Spring 2.1.0 中的启动为任务执行器提供自动配置,并用于 @EnableAsync
和 Spring MVC 异步支持。
应用程序不需要任务执行器 bean/webMvcConfigurer 配置。所以删除你拥有的那个应该是好的。
您可以使用带有 spring.task.execution.*
的应用程序 properties/yml 文件进行调整。
spring.task.execution.shutdown.await-termination=true
spring.task.execution.shutdown.await-termination-period=60
可以找到完整列表here
或
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(5);
taskExecutor.waitForTasksToCompleteOnShutdown(true);
taskExecutor.setAwaitTerminationSeconds(60);
return taskExecutor;
}
我有一个 Spring 引导应用程序,它使用 AsyncTaskExecutor
(数字是预定义的)
线程执行一个无限循环,从一些队列和进程对象中读取,所以我没有真正的拒绝策略机制(比如接受 tasks
的线程池)
问题是当应用程序关闭时,线程可能(并且很可能)忙于处理一个项目,该项目包括使用 MongoTemplate
对 Mongo 的操作。
因此,当应用程序关闭时,Mongo客户端会自动 close()
,然后我从 Mongo 收到一些错误,例如:
java.lang.IllegalStateException: The pool is closed
at com.mongodb.internal.connection.ConcurrentPool.get(ConcurrentPool.java:137)
at com.mongodb.internal.connection.DefaultConnectionPool.getPooledConnection(DefaultConnectionPool.java:262)
at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:103)
at com.mongodb.internal.connection.DefaultConnectionPool.get(DefaultConnectionPool.java:92)
at com.mongodb.internal.connection.DefaultServer.getConnection(DefaultServer.java:85)
如何优雅地关闭应用程序?例如在不关闭 MongoClient 的情况下中断线程?
代码:
Bean 创建:
@Bean
AsyncTaskExecutor getTaskExecutor() {
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
return executor;
}
只需通过以下方式执行:
executor.execute(runnable);
不要使用 SimpleAsyncTaskExecutor
- SimpleAsyncTaskExecutor 为每个请求创建一个新线程而不是使用 ThreadPoolTaskExecutor
并配置下面提到的两个属性。
/**
* Set whether to wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* <p>Default is "false", shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
* prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Note that Spring's container shutdown continues while ongoing tasks
* are being completed. If you want this executor to block and wait for the
* termination of tasks before the rest of the container continues to shut
* down - e.g. in order to keep up other resources that your tasks may need -,
* set the {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"}
* property instead of or in addition to this property.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
/**
* Set the maximum number of seconds that this executor is supposed to block
* on shutdown in order to wait for remaining tasks to complete their execution
* before the rest of the container continues to shut down. This is particularly
* useful if your remaining tasks are likely to need access to other resources
* that are also managed by the container.
* <p>By default, this executor won't wait for the termination of tasks at all.
* It will either shut down immediately, interrupting ongoing tasks and clearing
* the remaining task queue - or, if the
* {@link #setWaitForTasksToCompleteOnShutdown "waitForTasksToCompleteOnShutdown"}
* flag has been set to {@code true}, it will continue to fully execute all
* ongoing tasks as well as all remaining tasks in the queue, in parallel to
* the rest of the container shutting down.
* <p>In either case, if you specify an await-termination period using this property,
* this executor will wait for the given time (max) for the termination of tasks.
* As a rule of thumb, specify a significantly higher timeout here if you set
* "waitForTasksToCompleteOnShutdown" to {@code true} at the same time,
* since all remaining tasks in the queue will still get executed - in contrast
* to the default shutdown behavior where it's just about waiting for currently
* executing tasks that aren't reacting to thread interruption.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#awaitTermination
*/
public void setAwaitTerminationSeconds(int awaitTerminationSeconds) {
this.awaitTerminationSeconds = awaitTerminationSeconds;
}
相关部分
Set the maximum number of seconds that this executor is supposed to block on shutdown in order to wait for remaining tasks to complete their execution before the rest of the container continues to shut down. This is particularly useful if your remaining tasks are likely to need access to other resources that are also managed by the container.
您可以使用 spring 自动配置来配置以控制任务执行属性(首选)或使用 @Bean
注释
Spring 2.1.0 中的启动为任务执行器提供自动配置,并用于 @EnableAsync
和 Spring MVC 异步支持。
应用程序不需要任务执行器 bean/webMvcConfigurer 配置。所以删除你拥有的那个应该是好的。
您可以使用带有 spring.task.execution.*
的应用程序 properties/yml 文件进行调整。
spring.task.execution.shutdown.await-termination=true
spring.task.execution.shutdown.await-termination-period=60
可以找到完整列表here
或
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(5);
taskExecutor.waitForTasksToCompleteOnShutdown(true);
taskExecutor.setAwaitTerminationSeconds(60);
return taskExecutor;
}