英文:
Safe way to "unwrap" a Mono in a webflux/reactor stream?
问题
我目前正在使用一个库,该库利用了Spring WebFlux和Project Reactor。我主要处理的领域是响应式流结束并且数据需要再次返回到同步的阻塞世界中。这是不可避免的,因为我将与之交互的方法不具有响应式意识(且不可修改)。我是响应式编程的新手,所以不确定如何解决这个问题。
我使用了一个类似于以下内容的接口:
interface Resolver {
Mono<Object> resolve(HttpRequest request);
}
我有一个类,它使用上述接口的多个实现来获取一些数据。最终我得到了一个像这样的HashMap
:
Mono<Map<String, Mono<Object>>> resolvedData;
在这一点上,我实际上需要"解开" HashMap
中 Mono<Object>
值,获取它们的实际值,就像这样:
Mono<Map<String, Object>> actualResolvedData;
我似乎无法找到一个干净的方法来做到这一点。每当我尝试直接调用 block()
时,会出现以下异常:
block()/blockFirst()/blockLast() are blocking, which is not supported in thread
我对这个异常有点理解,但同时我不知道如何避免它。我知道这不是"理想的"响应式编程,因为目标是不进行阻塞。但由于这是需要这些数据的地方,我无法控制。我是否遗漏了一些简单的东西?我已经盯着这段代码看了几天,但对于解决这个问题没有更进一步。如果有任何建议,将不胜感激。谢谢。
英文:
I am currently working with a library that makes use of Spring WebFlux and Project Reactor. The main area I am working in is where the reactive stream ends and the data needs to go back into the synchronized, blocking world again. This is unavoidable as the methods I will be interacting with are not reactive-aware (and not modifiable). I'm a newbie at reactive programming so I'm not sure how to go about fixing this.
I am using an interface that looks similar to this:
interface Resolver {
Mono<Object> resolve(HttpRequest request);
}
I have a class that uses several implementations of the above interface to get some data. I am ultimately left with a HashMap
like this:
Mono<Map<String, Mono<Object>>> resolvedData;
What I need at this point is to essentially "unwrap" the Mono<Object>
values in the HashMap
and have their actual values like this:
Mono<Map<String, Object>> actualResolvedData;
I can't seem to figure out a way to do this cleanly. Whenever I try to call block()
directly I get the following exception:
block()/blockFirst()/blockLast() are blocking, which is not supported in thread
I sort of understand the exception but at the same time I no idea how to go about avoiding it. I get that this is not "ideal" reactive programming as the objective is to not block. This is out of my control as this is the point where this data is needed. Am I missing something simple? I've been staring at this code for a few days now and no further along to figuring this out. Any advice would be greatly appreciated. Thanks.
答案1
得分: 0
感谢 @MartinTarjányi 协助解决我的问题。我找到了一种方法将 Resovler
接口的 Mono<Object>
输出在变成 Map<String, Object>
之前映射到 Tuple
。这样我就可以使用普通的 flatMap
来进行第一个转换(我在问题中称之为“解封”),然后在类似之前的 collectMap
中将 Tuple
转换为 Map
。完整的答案在上面的评论中,但这是代码最终的修正方式:
private Mono<Map<String, Object>> getValues(List<ResolvedData> resolvedData, HttpRequest httpRequest) {
return Flux.fromIterable(resolvedData).flatMap(data -> {
Resolver resolver = data.getResolver();
return resolver.resolve(httpRequest).map(resolvedValue -> Tuples.of(data.getName(), resolvedValue));
}).collectMap(Tuple2::getT1, Tuple2::getT2);
}
英文:
Many thanks to @MartinTarjányi for helping to solve my problem. I was shown a way to map the Mono<Object>
output of the Resovler
interface to a Tuple
before it was made into a Map<String, Object>
. That way I could use a regular flatMap
to do the first transformation (what I called the "unwrap" in the question) and then convert the Tuple
to a Map
in a collectMap
like before. The full answer is in the comments above but here is how the code was finally fixed:
private Mono<Map<String, Object>> getValues(List<ResolvedData> resolvedData, HttpRequest httpRequest) {
return Flux.fromIterable(resolvedData).flatMap(data -> {
Resolver resolver = data.getResolver();
return resolver.resolve(httpRequest).map(resolvedValue -> Tuples.of(data.getName(), resolvedValue));
}).collectMap(Tuple2::getT1, Tuple2::getT2);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论