这个问题我找不到正确的解决办法,我被困住了。假设我有这样的方法
@GET
@Path("/testingAsync")
public Uni<List<String>> testingMutiny() {
List<String> completeList = new ArrayList<>();
completeList.add("hello");
completeList.add("RestEasy");
List<String> finalList = new ArrayList<>();
completeList.forEach(e -> Uni.createFrom().item(e)
.onItem().delayIt().by(Duration.ofMillis(10000))
.map(value -> finalList.add(value.toUpperCase()))
.subscribe().asCompletionStage());
return Uni.createFrom().item(finalList);
}正如您所看到的,这个方法很简单,它只是从一个列表中获取值并将它们添加到第二个列表中,但是问题是什么?当您添加等待的.onItem().delayIt().by(Duration.ofMillis(10000))时,程序将返回一个空列表,一段时间后,它将只更新列表。我创建这个方法是为了模拟一个请求,这个请求的响应有一些延迟。
假设您使用两个不同的Uni访问了两个URL,然后尝试将它们组合起来,并将它们作为一个Uni返回。问题是,如果这两个URL中的一个由于某种原因而延迟,我们将返回列表为空,但我不希望这种情况发生,我希望列表完成100%,或者返回一个错误,如果它需要一段时间。
最好的办法是什么?我了解到,如果您添加了await(),您就阻塞了主线程,并且丢失了使用反应性库的所有价值,但我仍然找不到一种方法让它工作
编辑
我已经发现,我试图调用的外部URL需要大约5秒的时间来完成这项工作,所以我希望在创建Uni时停止代码,并在收到服务器的答复后继续。我在他们的文档(这里)中看到,我也可以调用await.indefinitely,但我接收到了The current thread cannot be blocked: vert.x-eventloop-thread-14。如何等待服务器的响应?
编辑2
我明白,有了字符串,我的问题就不那么有意义了,所以假设我有下面一个
@GET
@Path("/testingAsync")
public Uni<List<Car>> testingMutiny() {
//ALL THIS IS IN A FOR EACH FOR EVERY CAR
//HIT ENDPOINT GET DOORS
Uni<List<JsonObjectCar>> carDoorsUni = getDoors(variable1,
variable2, variable3);
//HIT ENDPOINT GET WHEELS
Uni<List<JsonObjectCar>> carWheelsUni = getWheels(variable1,
variable2, variable3);
//HIT ENDPOINT GET WINDOWS
Uni<List<JsonObjectCar>> carWindowsUni = getWindows(variable1,
variable2, variable3);
Uni.combine()
.all()
.unis(carDoorsUni, carWheelsUni, carWindowsUni)
.combinedWith((carDoors, carWheels, carWindows) -> {
//Check if cardoors is present and set the doors into the car object
Optional.of(carDoors)
.ifPresent(val -> car.setDoors(val.getDoors()));
Optional.of(carWheels)
.ifPresent(val -> car.setWheels(val.getWheels()));
Optional.of(carWindows)
.ifPresent(val -> car.setWindows(val.getWindows()));
return car;
}).subscribe().with(e-> System.out.println("Okay it worked"));
//END OF FOR EACH
//Return car (Should have been returned with new doors / wheels/ windows but instead its empty)
return Uni.createFrom().item(car);
}正如您在上面的代码中所看到的,它应该命中门/轮/窗的一些端点,并将它们设置到可变的汽车中,但实际上,所发生的情况是,汽车是空的,因为其中一个端点被延迟了,所以我返回一辆没有这些值的汽车。我想首先更新car对象,然后实际返回它。
发布于 2022-11-08 14:40:36
您可以这样重写该方法:
@GET
@Path("/testingAsync")
public Uni<List<String>> testingMutiny() {
List<Uni<String>> unis = new ArrayList<>();
List.of("hello", "RestEasy").forEach( e -> {
unis.add( Uni.createFrom().item( e )
.onItem().delayIt().by( Duration.ofMillis( 10000 ) ) );
} );
return Uni.combine().all().unis( unis )
.combinedWith( list -> (List<String>) list);
}注意,当您编写反应性代码时,您希望避免使用.await().indefinetly。无论如何,在使用Quarkus时不应该需要它,因为它识别异步API并相应地解释结果。
在使用Quarkus时,您也不需要订阅Uni或Multi,原因也是一样的。
基于前面的示例,您可以用端点重写用例,如下所示:
@GET
@Path("/testingAsync")
public Uni<Car> testingMutiny() {
Uni<List<JsonObjectCar>> carDoorsUni = getDoors(variable1, variable2, variable3);
Uni<List<JsonObjectCar>> carWheelsUni = getWheels(variable1,variable2, variable3);
Uni<List<JsonObjectCar>> carWindowsUni = getWindows(variable1,variable2, variable3);
return Uni.combine()
.all()
.unis(carDoorsUni, carWheelsUni, carWindowsUni)
.combinedWith(list -> {
// Result of carDoorsUni
List<JsonObjectCar> carDoors = list.get(0);
// Result of carWheelsUni
List<JsonObjectCar> carWheels = list.get(1);
// Result of carWindowsUni
List<JsonObjectCar> carWindows = list.get(2);
// Create a car instance with the previous results
Car car = createCar(...);
// You can also return a list of cars, but you need to change the return type of testingMutiny to Uni<List<Car>>
return car;
})
.invoke( () -> System.out.println("Okay it worked"));
}发布于 2022-11-08 12:23:46
您返回一个列表,但是Uni上的异步处理延迟了,所以您的列表将为空。
您应该尝试从创建的管道返回一个Uni (还可以看到collect()、toUni()将其放入列表),而不是执行订阅、收集结果并将其重新包装为Uni。
https://stackoverflow.com/questions/74347822
复制相似问题