Java 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

我在Spring集成应用程序中有以下基于注释的配置:

@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;
}