当消息计数大于并发消费者数时,如何使用Spring IntegrationFlow中所需的所有消息?

时间:2017-12-05 11:01:04

标签: java spring spring-integration spring-rabbit spring-integration-amqp

我有一个像这样定义的集成流:

IntegrationFlows.from(Amqp.inboundAdapter(connectionFactory, "queueName")
                    .id("id")
                    .autoStartup(autoStartup)
                    .concurrentConsumers(2)
                    .maxConcurrentConsumers(3)
                    .messageConverter(messageConverter()))
                    .aggregate(a -> a.correlationExpression("payload.entityId")
                                    .releaseExpression("size() eq iterator().next().payload.batchSize")
                                    .sendPartialResultOnExpiry(true)
                                    .groupTimeout(2000)
                                    .expireGroupsUponCompletion(true)
                                    .outputProcessor(myMessageGroupProcessor))
                    .handle(serviceActivatorBean, "myMethod", e -> e.advice(requestHandlerRetryAdviceForIntegrationFlow()))
                    .get();

其目的是对在"批次"中发送的若干相关消息进行分组。这是一个例子:

// Message 1
{ "name": "Message1", 
  "entityId": "someId"
  "batchSize": 2,
  "batchIndex": 1, 
  .... }

// Message 2
{ "name": "Message2",
  "entityId": "someId"
  "batchSize": 2,
  "batchIndex": 2, 
  .... }

由于here所述的原因,我们使用手动确认:使用RabbitMQ以避免丢失消息。

集成流程适用于2号批次,但只要批次中有超过2封邮件,我们就会遇到麻烦:

[my-service] 2017-12-04 17:46:07.966  INFO 1 --- [ask-scheduler-5] x.y.EntityUpdater : Will update entity [entitId] from messages: Message1, Message2 
[my-service] 2017-12-04 17:46:09.976  INFO 1 --- [ask-scheduler-3] x.y.EntityUpdater : Will update entity [entitId] from messages: Message3

请注意,记录消息之间的时间大约为2秒(即我们已确认为groupTimeout)。

我怀疑这是因为Spring消耗了2条消息(自动不是ack:ed),然后聚合等待第3条消息(因为batchSize在这种情况下是3)。但是这个消息永远不会在2秒窗口内消耗,因为只有两个并发消费者。

concurrentConsumers计数增加到3可以解决特定问题。问题是我们不知道我们收到的批次的大小,它们可能非常大,可能大小为50左右。这意味着仅仅增加concurrentConsumers不是一个可行的选择。

在Spring中处理此问题的适当方法是什么?

1 个答案:

答案 0 :(得分:2)

正如我在comments to this answer ...

中所讨论的那样

使用此模式时,concurrency * prefetch必须足够大,以包含所有未完成批次的消息。

出于这个原因,我不赞成使用该模式,除非你有相当可预测的数据。