簡體   English   中英

如何合並多個 vertx Web 客戶端響應

[英]How to merge multiple vertx web client responses

我是 vertx 和異步編程的新手。

我有 2 個通過事件總線進行通信的 Verticle,如下所示:

//API垂直

 public class SearchAPIVerticle extends AbstractVerticle {
    
    
        public static final String GET_USEARCH_DOCS = "get.usearch.docs";
    
        @Autowired
        private Integer defaultPort;
    
        private void sendSearchRequest(RoutingContext routingContext) {
    
            final JsonObject requestMessage = routingContext.getBodyAsJson();
    
            final EventBus eventBus = vertx.eventBus();
            eventBus.request(GET_USEARCH_DOCS, requestMessage, reply -> {
                if (reply.succeeded()) {
                    Logger.info("Search Result = " + reply.result().body());
                    routingContext.response()
                            .putHeader("content-type", "application/json")
                            .setStatusCode(200)
                            .end((String) reply.result().body());
                } else {
                    Logger.info("Document Search Request cannot be processed");
                    routingContext.response()
                            .setStatusCode(500)
                            .end();
                }
            });
        }
    
         
        @Override
        public void start() throws Exception {
            Logger.info("Starting the Gateway service (Event Sender) verticle");
            // Create a Router
            Router router = Router.router(vertx);
    
            //Added bodyhandler so we can process json messages via the event bus
            router.route().handler(BodyHandler.create());
    
            //    Mount the handler for incoming requests
            // Find documents
            router.post("/api/search/docs/*").handler(this::sendSearchRequest);
            
            // Create an HTTP Server using default options
            HttpServer server = vertx.createHttpServer();
            // Handle every request using the router
            server.requestHandler(router)
                    //start listening on port 8083
                    .listen(config().getInteger("http.port", 8083)).onSuccess(msg -> {
                        Logger.info("*************** Search Gateway Server started on "
                                + server.actualPort() + " *************");
                    });
        }
    
        @Override
        public void stop(){
           //house keeping
        }
    
    }

//下面是目標verticle應該進行多個Web客戶端調用並合並響應。

  @Component
        public class SolrCloudVerticle extends AbstractVerticle {
        
            public static final String GET_USEARCH_DOCS = "get.usearch.docs";
        
            @Autowired
            private SearchRepository searchRepositoryService;
        
            @Override
            public void start() throws Exception {
                Logger.info("Starting the Solr Cloud Search Service (Event Consumer) verticle");
        
                super.start();
        
                ConfigStoreOptions fileStore = new ConfigStoreOptions().setType("file")
                        .setConfig(new JsonObject().put("path", "conf/config.json"));
                ConfigRetrieverOptions configRetrieverOptions = new ConfigRetrieverOptions()
                        .addStore(fileStore);
                ConfigRetriever configRetriever = ConfigRetriever.create(vertx, configRetrieverOptions);
                configRetriever.getConfig(ar -> {
                    if (ar.succeeded()) {
                        JsonObject configJson = ar.result();
                        EventBus eventBus = vertx.eventBus();
        
                        eventBus.<JsonObject>consumer(GET_USEARCH_DOCS).handler(getDocumentService(searchRepositoryService, configJson));
               
                        Logger.info("Completed search service event processing");
        
                    } else {
                        Logger.error("Failed to retrieve the config");
                    }
                });
        
            }
        
      





      private Handler<Message<JsonObject>> getDocumentService(SearchRepository searchRepositoryService, JsonObject configJson) {
                           
                            return requestMessage -> vertx.<String>executeBlocking(future -> {
                               
                    
                                try {
            
            //I need to incorporate the logic here that adds futures to list and composes the compositefuture

/*
//Below is my logic to populate the future list
WebClient client = WebClient.create(vertx);
                List<Future> futureList = new ArrayList<>();
                for (Object collection : searchRepositoryService.findAllCollections(configJson).getJsonArray(SOLR_CLOUD_COLLECTION).getList()) {
                    Future<String> future1 = client.post(8983, "127.0.0.1", "/solr/" + collection + "/query")
                            .expect(ResponsePredicate.SC_OK)
                            .sendJsonObject(requestMessage.body())
                            .map(HttpResponse::bodyAsString).recover(error -> {
                                System.out.println(error.getMessage());
                                return Future.succeededFuture();
                            });
                    futureList.add(future1);
                }
//Below is the CompositeFuture logic, but the logic and construct does not make sense to me. What goes as first and second argument of executeBlocking method

 /*CompositeFuture.join(futureList)
                        .onSuccess(result -> {
                             result.list().forEach( x -> {
                                 if(x != null){
                                     requestMessage.reply(result.result());
                                 }
                             }
                             );
                        })
                        .onFailure(error -> {
                            System.out.println("We should not fail");
                        })

*/
        
                     future.complete("DAO returns a Json String");
                                 
             
                                } catch (Exception e) {
                                    future.fail(e);
                                }
                            }, result -> {
                                if (result.succeeded()) {
                                    requestMessage.reply(result.result());
                                } else {
                                    requestMessage.reply(result.cause()
                                            .toString());
                                }
                            });
                        }
                    
                   }

我能夠使用 org.springframework.web.reactive.function.client.WebClient 調用從多個 Web 客戶端調用組合我的搜索結果,而不是使用 Future<io.vertx.ext.web.client.WebClient> 和 CompositeFuture . 我試圖避免混合 Springboot 和 Vertx,但不幸的是 Vertx CompositeFuture 在這里不起作用:

//This method supplies the parameter for the future.complete(..) line in getDocumentService(SearchRepository,JsonObject) 
 private List<JsonObject> findByQueryParamsAndDataSources(SearchRepository searchRepositoryService,
                                                   JsonObject configJson,
                                                   JsonObject requestMessage)
            throws SolrServerException, IOException {
        List<JsonObject> searchResultList = new ArrayList<>();
        for (Object collection : searchRepositoryService.findAllCollections(configJson).getJsonArray(SOLR_CLOUD_COLLECTION).getList()) {
           
            searchResultList.add(new JsonObject(doSearchPerCollection(collection.toString(), requestMessage.toString())));
        }
        return aggregateMultiCollectionSearchResults(searchResultList);
    }

public String doSearchPerCollection(String collection, String message) {

        org.springframework.web.reactive.function.client.WebClient client =
                org.springframework.web.reactive.function.client.WebClient.create();

        return client.post()
                .uri("http://127.0.0.1:8983/solr/" + collection + "/query")
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(message.toString()))
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

    private List<JsonObject> aggregateMultiCollectionSearchResults(List<JsonObject> searchList){
        //TODO: Search result aggregation
        return searchList;
    }

我的用例是第二個 verticle 應該進行多個 vertx Web 客戶端調用,並且應該組合響應。 如果 API 調用失敗,我想記錄錯誤並繼續處理和合並來自其他調用的響應。 請對我上面的代碼如何適應處理用例有任何幫助嗎?

我正在查看 vertx CompositeFuture,但還沒有看到任何進展或有用的示例!

您正在尋找的內容可以通過Future 協調完成,並進行一些額外的處理:

CompositeFuture.join(future1, future2, future3).onComplete(ar -> {
    if (ar.succeeded()) {
        // All succeeded
    } else {
        // All completed and at least one failed
    }
});

連接組合一直等到所有未來都完成,無論是成功還是失敗。 CompositeFuture.join 接受多個期貨參數(最多 6 個)並返回一個期貨,當所有期貨都成功時成功,當所有期貨都完成並且至少其中一個失敗時失敗

使用 join 您將等待所有 Futures 完成,問題是如果其中一個失敗,您將無法從其他人那里獲得響應,因為 CompositeFuture 將失敗。 為避免這種情況,您應該在每個 Futures 上添加Future<T> recover(Function<Throwable, Future<T>> mapper) ,您應該在其中記錄錯誤並傳遞一個空響應,以便未來不會失敗。

這是一個簡短的例子:

Future<String> response1 = client.post(8887, "localhost", "work").expect(ResponsePredicate.SC_OK).send()
    .map(HttpResponse::bodyAsString).recover(error -> {
        System.out.println(error.getMessage());
        return Future.succeededFuture();
    });
Future<String> response2 = client.post(8887, "localhost", "error").expect(ResponsePredicate.SC_OK).send()
    map(HttpResponse::bodyAsString).recover(error -> {
        System.out.println(error.getMessage());
        return Future.succeededFuture();
    });

CompositeFuture.join(response2, response1)
    .onSuccess(result -> {
        result.list().forEach(x -> {
            if(x != null) {
                System.out.println(x);
            }
        });
    })
    .onFailure(error -> {
        System.out.println("We should not fail");
    });

編輯1:

CompositeFuture.join(Future...)的限制是 6 個 Future,如果您需要更多,可以使用: CompositeFuture.join(Arrays.asList(future1, future2, future3)); 您可以在其中傳遞無限數量的期貨。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM