让我们说我有两个发现特殊文件名的Verticle(例如,可能是任何东西)并将它们发布到事件总线,例如一个是从REST API中读取名称,另一个是从文件系统中读取名称:
ScanRestVerticle.java
/**
* Reads file names through an REST API
*/
public class ScanRestVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
HttpClientRequest req = vertx.createHttpClient().request(HttpMethod.GET, "BASE_URL", "URL");
req.toObservable()
.flatMap(HttpClientResponse::toObservable)
.lift(unmarshaller(Model.class))
.subscribe(c -> vertx.eventBus().publish("address", c.specialName()));
req.exceptionHandler(Throwable::printStackTrace);
req.end();
}
}
ScanFsVerticle.java
/**
* Reads file names from a file
*/
public class ScanFsVerticle.java extends AbstractVerticle {
@Override
public void start() throws Exception {
StringObservable.byLine(vertx.fileSystem()
.rxReadFile("myFileNames.txt")
.map(Buffer::toString)
.toObservable())
.subscribe(c -> vertx.eventBus().publish("address", c), e -> System.err.println(e.getMessage()));
}
}
这里的一切都很棒,但是,现在,我有一个Verticle,它将这些名称从事件总线中组合起来并在STD.OUT上打印出来:
PrintVerticle.java
public class PrintVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
vertx.eventBus()
.<JsonObject>consumer("address")
.bodyStream()
.toObservable()
.reduce(new JsonArray(), JsonArray::add)
.subscribe(j -> System.out.println(j.toString()));
}
问题是 reduce 在这里永远不会真正完成,因为事件总线正如我想的那样无限流。
那么我如何实际完成此操作并打印两个Verticle发布的名称?
注意:我在vert.x和rx中真的很新,我可能会遗漏一些碎片或弄错了,所以请不要&#39;判断:)
提前致谢。
编辑:我可以在此处拨打scan()
而不是reduce()
,以获得中间结果,但我如何获得scan().last()
?
答案 0 :(得分:1)
您正确假设,reduce()
运营商依赖onComplete()
事件来了解停止收集的位置。
虽然scan()
是累加器,它为源流的每个新发射发出累积值,因此扫描将为您提供中间结果。
这里的问题是,您使用EventBus
,概念上,EventBus
是无限流,因此永远不应该调用onComplete()
。从技术上讲,当你close()
`EventBus时,它可能会被调用,但我想你不应该依赖它而不是它。
如果你想使用EventBus,你应该以某种方式结束你的PrintVerticle
流,这样你就会有onComplete()
个事件。例如,您可以使用EventBus
发布一些事件,这些事件发布了两个观察到的顶点中的每一个结束。然后,您可以压缩它并在发出此2个事件后在takeUntil()
结束您的流(使用PrintVerticle
)。
像这样:
Observable vertice1EndStream = vertx.eventBus()
.<JsonObject>consumer("vertice1_end")
.bodyStream()
.toObservable();
Observable vertice2EndStream = vertx.eventBus()
.<JsonObject>consumer("vertice2_end")
.bodyStream()
.toObservable()
Observable bothVerticesEndStream = Observable.zip(vertice1EndStream, vertice2EndStream, (vertice1, vertice1) -> new Object());
vertx.eventBus()
.<JsonObject>consumer("address")
.bodyStream()
.toObservable()
.takeUntil(bothVerticesEndStream)
.reduce(new JsonArray(), JsonArray::add)
.subscribe(j -> System.out.println(j.toString()));
另一种选择是直接使用2个流而不是EventBus
。将它们合并在一起,然后使用reduce()
,因为这两个流是有限的,你不会有问题。