我们有一个多组件应用程序,在组件之间提供了Reactive Streams API。某些组件是使用Akka Streams实现的,而其他组件是使用例如反应堆。
在一个组件中,我们注意到尽管提供的发布者提供了记录,但Streams并未处理任何消息。我将问题归结为以下情况:
Publisher<String> stringPublisher = Source
.from(Lists.newArrayList("Hello", "World", "!"))
.runWith(Sink.asPublisher(AsPublisher.WITH_FANOUT), materializer);
Source<String, NotUsed> allMessages = Source
.fromPublisher(stringPublisher)
.toMat(BroadcastHub.of(String.class, 256), Keep.right())
.run(materializer);
allMessages
.runForeach(System.out::println, materializer)
.toCompletableFuture()
.get();
一个组件提供了一个发布者(由于API使用的是Reactive Streams API,而不是Akka Streams API,因此它必须是发布者)。该发布者是从另一个Akka Streams源创建的,并使用Sink.asPublisher
变成了发布者。
现在我们从发布商开始使用BroadcastHub实现流时,根本不会处理任何记录。
我在Reactor Publisher上尝试了相同的操作
Publisher<String> stringPublisher = Flux.fromIterable(Sink.asPublisher(AsPublisher.WITH_FANOUT), materializer);
这按预期工作。不幸的是,我不能排除其他组件从Akka流源创建其发布者的情况。
有人知道哪里出了问题吗?
答案 0 :(得分:0)
我现在知道如何解决它,如果我开始使用mapMaterializedValue中的resultH广播源的话,它会起作用:
Publisher<String> stringPublisher = Source
.from(Lists.newArrayList("Hello", "World", "!"))
.runWith(Sink.asPublisher(AsPublisher.WITH_FANOUT), materializer);
Source
.fromPublisher(stringPublisher)
.alsoToMat(BroadcastHub.of(String.class, 256), Keep.right())
.mapMaterializedValue(source -> source
.runWith(Sink.foreach(System.out::println, materializer))
.run(materializer)
.toCompletableFuture()
.get();
编辑: TL; DR:解释在Lightbend Forum中说明:
这里发生的是,当您附加另一个流时,主流已经完成。有时候,在完成之前看到一些元素可能足够快。
---
因此,看来,在将使用者附加到BroadcastHub创建的Source之前,BroadcastHub实际上已经删除了元素。
文档说它不会不会掉落:
如果没有订阅者连接到该集线器,则它将不丢弃任何元素,而是对上游生产者施加反压,直到订阅者到达为止。
https://doc.akka.io/docs/akka/current/stream/stream-dynamic.html
实际上,在大多数情况下都是如此,但是我发现某些情况下行为不正确:
public void testBH3() throws ExecutionException, InterruptedException {
Publisher<String> stringPublisher = Source
.from(Lists.newArrayList("Hello", "World", "!"))
.runWith(Sink.asPublisher(AsPublisher.WITH_FANOUT), materializer);
Source<String, NotUsed> allMessages = Source
.fromPublisher(stringPublisher)
.toMat(BroadcastHub.of(String.class, 256), Keep.right())
.run(materializer);
allMessages
.runForeach(System.out::println, materializer)
.toCompletableFuture()
.get();
}
public void repeat() throws ExecutionException, InterruptedException {
for (int i = 0; i < 100; i++) {
testBH3();
System.out.println("------");
}
}
这在100例案例中的3例中有效。但是以下情况在所有情况下都有效(我只是添加了一个油门以使元素生成速度更慢):
public void testBH3() throws ExecutionException, InterruptedException {
Publisher<String> stringPublisher = Source
.from(Lists.newArrayList("Hello", "World", "!"))
.runWith(Sink.asPublisher(AsPublisher.WITH_FANOUT), materializer);
Source<String, NotUsed> allMessages = Source
.fromPublisher(stringPublisher)
.throttle(1, Duration.ofSeconds(1))
.toMat(BroadcastHub.of(String.class, 256), Keep.right())
.run(materializer);
allMessages
.runForeach(System.out::println, materializer)
.toCompletableFuture()
.get();
}
因此,在我看来,当没有接收器连接时,BroadcastHub有时会丢弃元素。