终止并从事件总线获取结果

时间:2017-04-24 07:56:00

标签: java rx-java vert.x

让我们说我有两个发现特殊文件名的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()

1 个答案:

答案 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(),因为这两个流是有限的,你不会有问题。