我想发送多条消息,这些消息将异步遍历同一条路径,并能够知道所有处理何时完成。
由于我需要知道每条路线何时终止,我想到了使用
ProducerTemplate#asyncRequestBody
使用 InOut 模式,以便在返回的Future
对象上调用get
将阻塞,直到路由终止。
到目前为止一切顺利,每个请求都异步发送到路由,循环遍历所有Future调用get方法将阻塞所有请求 我的路线已经完成。
问题在于,虽然请求是异步发送的,但我希望它们也可以并行使用。
例如,假设P是ProducerTemplate
,R n beeing请求,E n 是端点 - 我想要的是:
-> R0 -> from(E1).to(E2).to(E3) : done.
/
P -> R1 -> from(E1).to(E2).to(E3) : done.
\
-> R2 -> from(E1).to(E2).to(E3) : done.
^__ Requests consumed in parallel.
经过一些研究后,我偶然发现Competing Consumers并行执行,增加了更多的消费者。
但是,由于同时存在多个执行,这会减慢每条路由的执行速度,导致某些ExchangeTimedOutException
:
The OUT message was not received within: 20000 millis due reply message with correlationID...
因为我发送 InOut 请求,所以并不奇怪。但实际上,我并不真正关心这种反应,我只是用它来知道
当我的路线终止时我会使用 InOnly (ProducerTemplate#asyncSendBody
),但调用Future#get
不会阻止,直到
整个任务完成。
是否有另一种替代方法可以异步发送请求并检测它们何时完成?
请注意,在我的情况下,更改超时不是一个选项。
答案 0 :(得分:1)
我的第一直觉是建议使用NotifyBuilder来跟踪处理,更具体地说,使用whenBodiesDone
来定位特定的身体。
修改强>
这是一个简单的实现,但确实证明了一点:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Component
public static class ParallelProcessingRouteBuilder extends RouteBuilder {
@Override
public void configure() throws Exception {
from("seda:test?concurrentConsumers=5")
.routeId("parallel")
.log("Received ${body}, processing")
.delay(5000)
.log("Processed ${body}")
.stop();
from("timer:testStarter?delay=3000&period=300000")
.routeId("test timer")
.process(exchange -> {
// messages we want to track
List<Integer> toSend = IntStream.range(0, 5).boxed().collect(toList());
NotifyBuilder builder = new NotifyBuilder(getContext())
.fromRoute("parallel")
.filter(e -> toSend.contains(e.getIn().getBody(Integer.class)))
.whenDone(toSend.size())
.create();
ProducerTemplate template = getContext().createProducerTemplate();
// messages we do not want to track
IntStream.range(10, 15)
.forEach(body -> template.sendBody("seda:test", body));
toSend.forEach(body -> template.sendBody("seda:test", body));
exchange.getIn().setBody(builder.matches(1, TimeUnit.MINUTES));
})
.log("Matched? ${body}");
}
}
}
以下是日志示例:
2016-08-06 11:45:03.861 INFO 27410 --- [1 - seda://test] parallel : Received 10, processing
2016-08-06 11:45:03.861 INFO 27410 --- [5 - seda://test] parallel : Received 11, processing
2016-08-06 11:45:03.864 INFO 27410 --- [2 - seda://test] parallel : Received 12, processing
2016-08-06 11:45:03.865 INFO 27410 --- [4 - seda://test] parallel : Received 13, processing
2016-08-06 11:45:03.866 INFO 27410 --- [3 - seda://test] parallel : Received 14, processing
2016-08-06 11:45:08.867 INFO 27410 --- [1 - seda://test] parallel : Processed 10
2016-08-06 11:45:08.867 INFO 27410 --- [3 - seda://test] parallel : Processed 14
2016-08-06 11:45:08.867 INFO 27410 --- [4 - seda://test] parallel : Processed 13
2016-08-06 11:45:08.868 INFO 27410 --- [2 - seda://test] parallel : Processed 12
2016-08-06 11:45:08.868 INFO 27410 --- [5 - seda://test] parallel : Processed 11
2016-08-06 11:45:08.870 INFO 27410 --- [1 - seda://test] parallel : Received 0, processing
2016-08-06 11:45:08.872 INFO 27410 --- [4 - seda://test] parallel : Received 2, processing
2016-08-06 11:45:08.872 INFO 27410 --- [3 - seda://test] parallel : Received 1, processing
2016-08-06 11:45:08.872 INFO 27410 --- [2 - seda://test] parallel : Received 3, processing
2016-08-06 11:45:08.872 INFO 27410 --- [5 - seda://test] parallel : Received 4, processing
2016-08-06 11:45:13.876 INFO 27410 --- [1 - seda://test] parallel : Processed 0
2016-08-06 11:45:13.876 INFO 27410 --- [3 - seda://test] parallel : Processed 1
2016-08-06 11:45:13.876 INFO 27410 --- [4 - seda://test] parallel : Processed 2
2016-08-06 11:45:13.876 INFO 27410 --- [5 - seda://test] parallel : Processed 4
2016-08-06 11:45:13.876 INFO 27410 --- [2 - seda://test] parallel : Processed 3
2016-08-06 11:45:13.877 INFO 27410 --- [r://testStarter] test timer : Matched? true
您会注意到NotifyBuilder
在结果匹配后如何返回结果。
答案 1 :(得分:0)
如果您知道您正在使用的每批消息都包含X消息,则可以在并行处理结束时使用aggregator。对于您的示例,每组消息都有自己唯一的标头标记,将由聚合器选取。在所有消息都是进程并且所有消息都已在聚合器中结束之后,您可以将消息聚合到您想要的任何格式并返回它们。