问题描述
我需要通过 Vertx 客户端将一个微服务连接到另一个微服务。在代码中,我正在检查另一个微服务是否关闭,然后在失败时它应该创建一些 JsonObject,以 solrError 作为键,失败消息作为值。如果出现 solr 错误,我的意思是如果其他微服务关闭,通过负载平衡调用 solr,那么它应该抛出一些错误响应。但是 Vertx 客户端需要一些时间来检查失败,当检查条件时,jsonobject 中没有 solrError,因为 Vertx 客户端需要一些时间来检查失败,因此条件失败并且 resp 为空。为了避免这种情况,可以做些什么来使 Vertx 客户端在检查 solrError 的条件之前失败并返回内部服务器错误响应?
代码如下:
solrQueryService.executeQuery(query).subscribe().with(jsonObject -> {
ObjectMapper objMapper = new ObjectMapper();
SolrOutput solrOutput = new SolrOutput();
List<Doc> docs = new ArrayList<>();
try {
if(null != jsonObject.getMap().get("solrError")){
resp = Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new BaseException(
exceptionService.processSolrDownError(request.header.referenceId))
.getResponse()).build();
}
solrOutput = objMapper.readValue(jsonObject.toString(),SolrOutput.class);
if (null != solrOutput.getResponse()
&& CollectionUtils.isNotEmpty(solrOutput.getResponse().getDocs())) {
docs.addAll(solrOutput.getResponse().getDocs());
uniDocList = Uni.createFrom().item(docs);
}
} catch (JsonProcessingException e) {
e.printstacktrace();
}
});
if(null!=resp && resp.getStatus() !=200) {
return resp ;
}
SolrQueryService is preparing query and send out URL and query to Vertx web client as below :
public Uni<JsonObject> search(URL url,SolrQuery query,Integer timeout) {
int port = url.getPort();
if (port == -1 && "https".equals(url.getProtocol())) {
port = 443;
}
if (port == -1 && "http".equals(url.getProtocol())) {
port = 80;
}
HttpRequest<Buffer> request = client.post(port,url.getHost(),url.getPath()).timeout(timeout);
return request.sendJson(query).map(resp -> {
return resp.bodyAsJsonObject();
}).onFailure().recoverWithUni(f -> {
return Uni.createFrom().item(new JsonObject().put("solrError",f.getMessage()));
});
}
解决方法
我没有使用过 Vertx 客户端,但假设它是响应式和非阻塞的。假设是这种情况,您的代码似乎混合了命令式和反应式结构。第一行中的 subscribe 是响应式的,当服务器响应客户端请求时,将调用您提供的 lambda。但是,在订阅之后,您有命令式代码在 lambda 甚至有机会被调用之前运行,因此您的检查和对“resp”对象的访问永远不会是 lambda 本身发生的事情的结果。
您需要将所有代码移动到 lambda 中,或者至少将后续代码链添加到订阅的结果上。