Java Spring集成轮询器有时运行一次,然后停止
我在Spring集成应用程序中有以下基于注释的配置:Java Spring集成轮询器有时运行一次,然后停止,java,spring,spring-integration,Java,Spring,Spring Integration,我在Spring集成应用程序中有以下基于注释的配置: @Bean(name = PollerMetadata.DEFAULT_POLLER) public PollerMetadata defaultPoller(@Value("${poll-interval}") int pollInterval) { return Pollers.fixedRate(pollInterval).maxMessagesPerPoll(1).get(); } @Bean @InboundChannel
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller(@Value("${poll-interval}") int pollInterval) {
return Pollers.fixedRate(pollInterval).maxMessagesPerPoll(1).get();
}
@Bean
@InboundChannelAdapter(value = "httpRequestChannel", poller = @Poller(PollerMetadata.DEFAULT_POLLER),
autoStartup = "${auto-start:true}")
public MessageSource<String> httpRequestTrigger() {
Expression expression = new SpelExpressionParser().parseExpression(
"#{@timeService.getLastQueryTime()}",
new TemplateParserContext("#{", "}"));
return new ExpressionEvaluatingMessageSource<>(expression, String.class);
}
@Bean
@Qualifier("httpRequestChannel")
public MessageChannel httpRequestChannel() {
return new RendezvousChannel();
}
@Bean
@ServiceActivator(inputChannel = "httpRequestChannel", poller = @Poller(fixedRate="100"))
public MessageHandler httpRequestExecutingMessageHandler(
URI backendURI,
@Qualifier("httpReplyChannel") MessageChannel httpReplyChannel,
RestTemplate restTemplate,
@Qualifier("filterExpression") Expression filterExpression
) {
HttpRequestExecutingMessageHandler messageHandler = new HttpRequestExecutingMessageHandler(
backendURI.toString() + "?filter={filter}", restTemplate);
messageHandler.setHttpMethod(HttpMethod.GET);
messageHandler.setExpectedResponseType(String.class);
messageHandler.setOutputChannel(httpReplyChannel);
messageHandler.setExpectReply(true);
messageHandler.setSendTimeout(1000);
Map<String, Expression> uriVariableExpressions = new HashMap<>();
uriVariableExpressions.put("filter", filterExpression);
messageHandler.setUriVariableExpressions(uriVariableExpressions);
return messageHandler;
}
@Bean
@Qualifier("httpReplyChannel")
public MessageChannel httpReplyChannel() {
return new DirectChannel();
}
请参阅bean-默认情况下它只有10个线程
当队列通道处于混合状态时,线程在receiveTimeout
期间暂停(默认情况下为1秒)。如果您有很多队列通道,您可能会经历线程饥饿
另外,您通常不需要太多的队列通道;通常情况下,在一个流程中,单线程切换就足够了。Gary Russell在评论中帮了我的忙,所以我想我会发布解决方案,以防有人遇到同样的问题。问题根本不在于轮询器,而在于
HttpRequestExecutingMessageHandler
。stacktrace显示处于以下状态的task-scheduler-2
线程挂起:
"task-scheduler-2@4837" prio=5 tid=0x14 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(SocketInputStream.java:-1)
这表明对后端的请求已挂起。消息处理程序使用的restemplate
上没有设置超时,因此线程将永远等待一个永远不会出现的请求,这导致整个应用程序看起来好像已经停止了。我的解决方案是将以下clienthtprequestfactory
添加到restemplate
bean中:
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(500);
factory.setConnectTimeout(500);
return factory;
}
设置非空读取和连接超时会导致应用程序在后端超时时记录异常,然后应用程序继续正常运行。非常感谢Gary Russell帮助我解决了这个令人困惑的问题。您是否在应用程序的其他地方使用了
taskScheduler
bean?通常,此类问题是由调度程序中的线程不足引起的(默认情况下,它只有10个线程)。调试的最佳方法是在遇到问题时进行线程转储,以查看调度程序线程正在执行的操作。还有大量其他通道,包括异步队列通道,因此我怀疑您是对的。我将增加调度程序上的线程数,看看它能做什么。在轮询器停止后,我得到了一个线程转储。两个任务调度器线程正在等待,一个是可运行的,显然停留在HTTP请求的中间。请将线程转储粘贴到您的问题中。您有一个有界队列通道(<代码> httpQuestStase?)作为Pelever之后的第一个通道——这是非常不寻常的。通道中的队列已满;因此,轮询将暂停,直到有足够的空间为止。我们需要在您对QueueChannel以外的任何内容发表的评论中解决这个问题HttpRequestExecutingMessageHandler
。您可以添加消息处理程序(和通道)配置吗?实际上只有两个队列通道;大多数其他频道设置为发布/订阅。我在将HttpRequestExecutingMessageHandler上的输出通道设置为QueueChannel以外的任何内容时遇到问题,但这可能是下一次的问题。无论如何,增加任务计划程序可用的线程数似乎很好地解决了我的问题。谢谢事实证明,这种解决方法有时只能解决问题。即使在将线程数增加到比我需要的大得多(例如100个线程)之后,轮询器有时仍然无法运行多次。
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(500);
factory.setConnectTimeout(500);
return factory;
}