I'm trying to convert XML configuration for using Spring's tasks framework into purely code configuration. I'm able to reproduce the functionality but whenever I shut down the war on the Tomcat server the task scheduler lives on, it hangs (it doesn't hang with XML configuration). I've debugged to inspect the instances of scheduler and executor but I'm not seeing a difference so I'm not sure what could be causing it to hang.
我正在尝试将使用Spring的任务框架的XML配置转换为纯粹的代码配置。我能够重现这些功能,但每当我关闭Tomcat服务器上的任务调度程序的战争时,它就会挂起(它不会挂起XML配置)。我已经调试过来检查调度程序和执行程序的实例,但是我没有看到差异所以我不确定是什么导致它挂起。
Here is the XML configuration that works:
以下是适用的XML配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<task:executor id="com.work.gwx.pix.executor"
pool-size="${pix.job.executor.pool.size:1-40}"
queue-capacity="${pix.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="com.work.gwx.pix.scheduler" pool-size="${pix.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="com.work.gwx.pix.executor" scheduler="com.work.gwx.pix.scheduler" />
<bean id='queueProcessor' class="com.work.gwx.queueing.QueueProcessor" />
</beans>
Here is the code configuration:
这是代码配置:
@EnableAsync
@EnableScheduling
@Configuration
public class TaskConfiguration implements AsyncConfigurer, SchedulingConfigurer {
@Value("${pix.job.executor.max.pool.size:1}")
private int executorMaxPoolSize;
@Value("${pix.job.executor.queue.capacity:0}")
private int executorQueueCapacity;
@Value("${pix.job.scheduler.pool.size:4}")
private int schedulerPoolSize;
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, new ThreadPoolTaskExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadFactory(new ThreadPoolTaskExecutor());
executor.initialize();
return executor;
}
@Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(pixTaskScheduler());
}
@Override
public Executor getAsyncExecutor() {
return pixExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
When I use setExecuteExistingDelayedTasksAfterShutdownPolicy(false)
in code configuration it does shut down but I'm worried that might have adverse effects as that is set to true when done via XML configuration. Also, I should note, the QueueProcessor class is doing the work I want and I don't mind if delayed executions get cancelled -- I just don't want currently executing threads to be abruptly cancelled.
当我在代码配置中使用setExecuteExistingDelayedTasksAfterShutdownPolicy(false)时,它会关闭,但我担心可能会产生不利影响,因为在通过XML配置完成时设置为true。另外,我应该注意,QueueProcessor类正在进行我想要的工作,我不介意延迟执行是否被取消 - 我只是不希望当前正在执行的线程被突然取消。
This is the message I get when it hangs:
这是我挂起时收到的消息:
SEVERE: The web application [/pix-queue-processor] appears to have started a thread named [ThreadPoolTaskExecutor-1] but has failed to stop it. This is very likely to create a memory leak.
严重:Web应用程序[/ pix-queue-processor]似乎已经启动了一个名为[ThreadPoolTaskExecutor-1]但未能阻止它的线程。这很可能造成内存泄漏。
Any ideas on what might be causing the hanging? Or, would using that commented out method let me do what I want (won't kill a running task but will cancel delayed tasks)?
关于什么可能导致悬挂的任何想法?或者,使用那个注释掉的方法让我做我想做的事情(不会杀死正在运行的任务但会取消延迟的任务)?
1 个解决方案
#1
Your Java based configuration isn't really a representation of the the XML configuration. There are at least 2 things that are different.
基于Java的配置实际上并不代表XML配置。至少有两件事是不同的。
- Your
TaskExecutor
has anotherTaskExecutor
wired as aThreadFactory
this isn't the case in XML and also starts anotherTaskExecutor
. - Your
TaskScheduler
uses a newTaskExecutor
whereas the xml configuration use the one configured.
您的TaskExecutor将另一个TaskExecutor连接为ThreadFactory,这不是XML中的情况,并且还启动另一个TaskExecutor。
您的TaskScheduler使用新的TaskExecutor,而xml配置使用配置的。
The have your task finished on shutdown you can set the waitForTasksToCompleteOnShutdown
property on the TaskExecutor
to true
then any pending tasks will be completed and no new tasks will be accepted.
让您的任务在关闭时完成,您可以将TaskExecutor上的waitForTasksToCompleteOnShutdown属性设置为true,然后任何待处理任务将完成,并且不会接受任何新任务。
Also the call to initialize
shouldn't be needed as the afterPropertiesSet
method will be called by Spring which in turn calls initialize
.
此外,不需要调用初始化,因为Spring将调用afterPropertiesSet方法,而Spring又调用initialize。
The following 2 bean definitions are more in line with the XML configuration (and you now have a single TaskExecutor
instead of 3 and it will first finish tasks before shutdown.
以下2个bean定义更符合XML配置(现在您只有一个TaskExecutor而不是3,它将在关闭之前完成任务。
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
#1
Your Java based configuration isn't really a representation of the the XML configuration. There are at least 2 things that are different.
基于Java的配置实际上并不代表XML配置。至少有两件事是不同的。
- Your
TaskExecutor
has anotherTaskExecutor
wired as aThreadFactory
this isn't the case in XML and also starts anotherTaskExecutor
. - Your
TaskScheduler
uses a newTaskExecutor
whereas the xml configuration use the one configured.
您的TaskExecutor将另一个TaskExecutor连接为ThreadFactory,这不是XML中的情况,并且还启动另一个TaskExecutor。
您的TaskScheduler使用新的TaskExecutor,而xml配置使用配置的。
The have your task finished on shutdown you can set the waitForTasksToCompleteOnShutdown
property on the TaskExecutor
to true
then any pending tasks will be completed and no new tasks will be accepted.
让您的任务在关闭时完成,您可以将TaskExecutor上的waitForTasksToCompleteOnShutdown属性设置为true,然后任何待处理任务将完成,并且不会接受任何新任务。
Also the call to initialize
shouldn't be needed as the afterPropertiesSet
method will be called by Spring which in turn calls initialize
.
此外,不需要调用初始化,因为Spring将调用afterPropertiesSet方法,而Spring又调用initialize。
The following 2 bean definitions are more in line with the XML configuration (and you now have a single TaskExecutor
instead of 3 and it will first finish tasks before shutdown.
以下2个bean定义更符合XML配置(现在您只有一个TaskExecutor而不是3,它将在关闭之前完成任务。
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}