Java Spring引导:通过控制涉及MongoClient的终止顺序,优雅地关闭
我有一个Spring启动应用程序,它使用一个Java Spring引导:通过控制涉及MongoClient的终止顺序,优雅地关闭,java,mongodb,multithreading,spring-boot,shutdown-hook,Java,Mongodb,Multithreading,Spring Boot,Shutdown Hook,我有一个Spring启动应用程序,它使用一个AsyncTaskExecutor(数字是预定义的)生成许多线程 线程执行一个无限循环,从一些队列和进程对象读取数据,因此我没有真正的拒绝策略机制(比如接受任务的线程池) 问题是,当应用程序关闭时,线程可能(也可能)忙于处理一个项目,其中包括使用MongoTemplate对Mongo进行操作 因此,当应用程序关闭时,MongoClient将自动被close()'d关闭,然后我从Mongo收到一些错误,如: java.lang.IllegalStateE
AsyncTaskExecutor
(数字是预定义的)生成许多线程
线程执行一个无限循环,从一些队列和进程对象读取数据,因此我没有真正的拒绝策略机制(比如接受任务的线程池
)
问题是,当应用程序关闭时,线程可能(也可能)忙于处理一个项目,其中包括使用MongoTemplate
对Mongo进行操作
因此,当应用程序关闭时,MongoClient将自动被close()
'd关闭,然后我从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)
如何才能优雅地关闭应用程序?e、 g.在不关闭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;
}
可以找到完整的列表
更多详情及
或
显示如何生成线程。您应该能够覆盖isInterrupted并与mongo进行优雅的断开连接。问题是,我仍然从mongo客户端收到错误,要求我在每次使用MongoTemplate时都尝试捕获非法状态异常。有没有办法绕过这个问题?这很奇怪。如果你能分享一个复制你的问题的例子(最好是github项目),那么我可以更深入地看一看,也请更新你的帖子来展示你现在拥有的东西。需要更多的细节。您可以使用@Async注释来运行任务吗?这些任务是如何安排的?您必须让spring为您管理任务。一些示例我将尝试@Async,正如您所建议的那样。当您将该方法标记为
@Async
,当调用该方法时,它将在单独的线程(从threadpool借用的线程)中运行,并由spring管理。因此,一旦spring引导关闭,它将优雅地完成执行任务的线程。您需要@EnableAsync
来启用异步处理。
spring.task.execution.shutdown.await-termination=true
spring.task.execution.shutdown.await-termination-period=60
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(5);
taskExecutor.waitForTasksToCompleteOnShutdown(true);
taskExecutor.setAwaitTerminationSeconds(60);
return taskExecutor;
}