如何使用RXJava顺序链接Vertx CompositeFuture?

如何使用RXJava顺序链接Vertx CompositeFuture?,java,asynchronous,rx-java,reactive-programming,vert.x,Java,Asynchronous,Rx Java,Reactive Programming,Vert.x,我需要以RxJava风格为依赖CompositeFuture按顺序链接Vertx CompositeFuture,以避免回调地狱 用例: 每个CompositeFuture.any/all都会执行一些返回未来的异步操作,比如myList1、myList2、myList3,但是我必须为CompositeFuture.any(myList1)设置wait,才能在执行CompositeFuture.any(myList2)之前完成并返回成功。当然,CompositeFuture本身是异步执行作业的,但

我需要以RxJava风格为依赖CompositeFuture按顺序链接Vertx CompositeFuture,以避免回调地狱

用例:

每个CompositeFuture.any/all都会执行一些返回未来的异步操作,比如myList1、myList2、myList3,但是我必须为CompositeFuture.any(myList1)设置wait,才能在执行CompositeFuture.any(myList2)之前完成并返回成功。当然,CompositeFuture本身是异步执行作业的,但只是针对它的一组操作,因为下一组作业必须在第一组作业顺利完成之后进行

以“回调地狱式”的方式进行操作将是:

    public static void myFunc(Vertx vertx, Handler<AsyncResult<CompositeFuture>> asyncResultHandler) {


        CompositeFuture.any(myList1 < Future >)
                .onComplete(ar1 -> {
                    if (!ar1.succeeded()) {
                        asyncResultHandler.handle(ar1);
                    } else {
                        CompositeFuture.any(myList2 < Future >)
                                .onComplete(ar2 -> {
                                            if (!ar2.succeeded()) {
                                                asyncResultHandler.handle(ar2);
                                            } else {
                                                CompositeFuture.all(myList3 < Future >)
                                                        .onComplete(ar3 -> {
                                                            asyncResultHandler.handle(ar3);
                                                        
    .... <ARROW OF CLOSING BRACKETS> ...
}

不起作用,所有的CompositeFuture都已处理,但没有测试是否成功完成,只有最后一个最终被传递给asyncResultHandler,后者将测试整体失败(但在我的代码中,它只检查最后一个)

我正在使用Vertx3.9.0和RxJava2VertxAPI

披露:我在Vertx方面有经验,但我对RxJava完全陌生。所以我很欣赏任何答案,从技术解决方案到概念解释

多谢各位

编辑(在@homerman的出色响应之后): 我需要具有与顺序相关的CompositeFuture的“回调地狱风格”完全相同的行为,即,在onComplete和test for completed with failure或success之后必须调用next。复杂性来自以下事实:

  • 我必须使用vertx CompositeAll/任何方法,而不是zip。Zip提供类似于CompositeAll的行为,但不是CompositeAny
  • CompositeAll/Any返回onComplete方法中已完成的未来。如果我像上面所示检查它,因为它是异步的,所以我将得到未解析的未来
  • CompositeAll/Any if failed不会抛出错误,但在onComplete内部会抛出failed future,因此我无法使用rxJava中的onError
  • 例如,我在rxComposite函数中尝试了以下更改:

        public static Single<CompositeFuture> rxLoadVerticlesAny(CompositeFuture previousResult, Vertx vertx, String deploymentName,
                                                                 List<Class<? extends Verticle>> verticles, JsonObject config) {
            previousResult.onComplete(event -> {
                        if (event.failed()) {
                            return Single.just(previousResult);
    
                        } else {
                            CompositeFuture compositeFuture = CompositeFuture.any(VertxDeployHelper.deploy(vertx, verticles, config));
                            return Single.just(compositeFuture);
                        }
                    }
            );
        }
    
    public static Single rxLoadVerticlesAny(CompositeFuture-previousResult,Vertx-Vertx,String-deploymentName,
    
    列出只是为了澄清一些事情

    每个CompositeFuture.any/all都执行一些返回的异步操作 未来,比如说我的未来,我的未来,但我必须等待 CompositeFuture.any(myList1)完成并返回之前的成功 正在执行CompositeFuture.any(myList2),并且从myList2到 myList3

    您提供了
    CompositeFuture.any()
    CompositeFuture.all()
    作为参考点,但您描述的行为与
    all()
    一致,也就是说,只有当其所有组成部分都这样做时,生成的复合才会成功

    就我的回答而言,我假设
    all()
    是您期望的行为。

    在RxJava中,异常触发的意外错误将导致流终止,并通过
    onError()
    回调将底层异常传递给观察者

    作为一个小演示,假设以下设置:

    final Single<String> a1 = Single.just("Batch-A-Operation-1");
    final Single<String> a2 = Single.just("Batch-A-Operation-2");
    final Single<String> a3 = Single.just("Batch-A-Operation-3");
    
    final Single<String> b1 = Single.just("Batch-B-Operation-1");
    final Single<String> b2 = Single.just("Batch-B-Operation-2");
    final Single<String> b3 = Single.just("Batch-B-Operation-3");
    
    final Single<String> c1 = Single.just("Batch-C-Operation-1");
    final Single<String> c2 = Single.just("Batch-C-Operation-2");
    final Single<String> c3 = Single.just("Batch-C-Operation-3");
    
    (如果您不熟悉,可以使用运算符组合作为输入提供的所有源的结果,以发出另一个/新源)

    在此流中,由于B的处理最终引发异常:

    • 流在B的执行期间终止
    • 将异常报告给观察者(即触发
      onError()
      处理程序)
    • C永远不会被处理
    但是,如果您想自己决定是否执行每个分支,那么您可以采取的一种方法是使用某种状态保持器将先前操作的结果向下传递,如下所示:

    class State {
      final String value;
      final Throwable error;
    
      State(String value, Throwable error) {
        this.value = value;
        this.error = error;
      }
    }
    
    然后可以修改流以有条件地执行不同的批处理,例如:

    Single
        .zip(a1, a2, a3, (s, s2, s3) -> {
          try {
            // Execute the A's here...
            return new State("A's completed successfully", null);
    
          } catch(Throwable t) {
            return new State(null, t);
          }
        })
        .flatMap((Function<State, SingleSource<State>>) s -> {
          if(s.error != null) {
            // If an error occurred upstream, skip this batch...
            return Single.just(s);
    
          } else {
            try {
              // ...otherwise, execute the B's
              return Single.just(new State("B's completed successfully", null));
              
            } catch(Throwable t) {
              return Single.just(new State(null, t));
            }
          }
        })
        .flatMap((Function<State, SingleSource<State>>) s -> {
          if(s.error != null) {
            // If an error occurred upstream, skip this batch...
            return Single.just(s);
    
          } else {
            try {
              // ...otherwise, execute the C's
              return Single.just(new State("C's completed successfully", null));
    
            } catch(Throwable t) {
              return Single.just(new State(null, t));
            }
          }
        })
        .subscribe(
            s -> {
              if(s.error != null) {
                System.out.println("## onSuccess with error: " + s.error.getMessage());
              } else {
                System.out.println("## onSuccess without error: " + s.value);
              }
            },
            t -> System.out.println("## onError(" + t.getMessage() + ")")
        );
    
    单一
    .zip(a1、a2、a3,(s、s2、s3)->{
    试一试{
    //执行A在这里。。。
    返回新状态(“A已成功完成”,空);
    }捕获(可丢弃的t){
    返回新状态(null,t);
    }
    })
    .flatMap((函数)s->{
    如果(s.error!=null){
    //如果上游发生错误,请跳过此批处理。。。
    单程返回。仅返回(s);
    }否则{
    试一试{
    //…否则,执行B的
    返回Single.just(新状态(“B's completed successfully”,null));
    }捕获(可丢弃的t){
    返回Single.just(新状态(null,t));
    }
    }
    })
    .flatMap((函数)s->{
    如果(s.error!=null){
    //如果上游发生错误,请跳过此批处理。。。
    单程返回。仅返回(s);
    }否则{
    试一试{
    //…否则,执行C
    返回Single.just(新状态(“C's completed successfully”,null));
    }捕获(可丢弃的t){
    返回Single.just(新状态(null,t));
    }
    }
    })
    .订阅(
    s->{
    如果(s.error!=null){
    System.out.println(“##onSuccess with error:”+s.error.getMessage());
    }否则{
    System.out.println(“##onSuccess无误:“+s.value”);
    }
    },
    t->System.out.println(“##onError”(+t.getMessage()+”)
    );
    
    在对Vertx源代码进行一些研究之后,我发现了一种公共方法,CompositeFuture的rx版本使用该方法将“传统”CompositeFuture转换为其rx版本。该方法是io.Vertx.reactivex.core.CompositeFuture.newInstance。通过这种变通方法,我可以使用我的传统方法,然后将其转换为rx链中使用的方法。Th这就是我想要的,因为改变现有的传统方法是有问题的

    以下是带有注释的代码:

    rxGetConfig(vertx)
            .flatMap(config -> {
                return rxComposeAny(vertx, config)
                        .flatMap(r -> rxComposeAny(vertx, config))
                        .flatMap(r -> rxComposeAll(vertx, config));
            })
            .subscribe(
                    compositeFuture -> {
                        compositeFuture.onSuccess(event -> startPromise.complete());
                    },
                    error -> startPromise.fail(error));
    
    
    public static Single<JsonObject> rxGetConfig(Vertx vertx) {
        ConfigRetrieverOptions enrichConfigRetrieverOptions = getEnrichConfigRetrieverOptions();
        // the reason we create new vertx is just to get an instance that is rx
        // so this ConfigRetriever is from io.vertx.reactivex.config, instead of normal io.vertx.config
        ConfigRetriever configRetriever = ConfigRetriever.create(io.vertx.reactivex.core.Vertx.newInstance(vertx), enrichConfigRetrieverOptions);
    
        return configRetriever.rxGetConfig();
    }
    
    public static Single<io.vertx.reactivex.core.CompositeFuture> rxComposeAny(Vertx vertx, JsonObject config) {
    
        // instead of adapted all the parameters of myMethodsThatReturnsFutures to be rx compliant, 
        // we create it 'normally' and the converts bellow to rx CompositeFuture
        CompositeFuture compositeFuture = CompositeFuture.any(myMethodsThatReturnsFutures(config));
    
        return io.vertx.reactivex.core.CompositeFuture
                .newInstance(compositeFuture)
                .rxOnComplete();
    }
    
    rxGetConfig(vertx)
    .flatMap(配置->{
    
    class State {
      final String value;
      final Throwable error;
    
      State(String value, Throwable error) {
        this.value = value;
        this.error = error;
      }
    }
    
    Single
        .zip(a1, a2, a3, (s, s2, s3) -> {
          try {
            // Execute the A's here...
            return new State("A's completed successfully", null);
    
          } catch(Throwable t) {
            return new State(null, t);
          }
        })
        .flatMap((Function<State, SingleSource<State>>) s -> {
          if(s.error != null) {
            // If an error occurred upstream, skip this batch...
            return Single.just(s);
    
          } else {
            try {
              // ...otherwise, execute the B's
              return Single.just(new State("B's completed successfully", null));
              
            } catch(Throwable t) {
              return Single.just(new State(null, t));
            }
          }
        })
        .flatMap((Function<State, SingleSource<State>>) s -> {
          if(s.error != null) {
            // If an error occurred upstream, skip this batch...
            return Single.just(s);
    
          } else {
            try {
              // ...otherwise, execute the C's
              return Single.just(new State("C's completed successfully", null));
    
            } catch(Throwable t) {
              return Single.just(new State(null, t));
            }
          }
        })
        .subscribe(
            s -> {
              if(s.error != null) {
                System.out.println("## onSuccess with error: " + s.error.getMessage());
              } else {
                System.out.println("## onSuccess without error: " + s.value);
              }
            },
            t -> System.out.println("## onError(" + t.getMessage() + ")")
        );
    
    rxGetConfig(vertx)
            .flatMap(config -> {
                return rxComposeAny(vertx, config)
                        .flatMap(r -> rxComposeAny(vertx, config))
                        .flatMap(r -> rxComposeAll(vertx, config));
            })
            .subscribe(
                    compositeFuture -> {
                        compositeFuture.onSuccess(event -> startPromise.complete());
                    },
                    error -> startPromise.fail(error));
    
    
    public static Single<JsonObject> rxGetConfig(Vertx vertx) {
        ConfigRetrieverOptions enrichConfigRetrieverOptions = getEnrichConfigRetrieverOptions();
        // the reason we create new vertx is just to get an instance that is rx
        // so this ConfigRetriever is from io.vertx.reactivex.config, instead of normal io.vertx.config
        ConfigRetriever configRetriever = ConfigRetriever.create(io.vertx.reactivex.core.Vertx.newInstance(vertx), enrichConfigRetrieverOptions);
    
        return configRetriever.rxGetConfig();
    }
    
    public static Single<io.vertx.reactivex.core.CompositeFuture> rxComposeAny(Vertx vertx, JsonObject config) {
    
        // instead of adapted all the parameters of myMethodsThatReturnsFutures to be rx compliant, 
        // we create it 'normally' and the converts bellow to rx CompositeFuture
        CompositeFuture compositeFuture = CompositeFuture.any(myMethodsThatReturnsFutures(config));
    
        return io.vertx.reactivex.core.CompositeFuture
                .newInstance(compositeFuture)
                .rxOnComplete();
    }