【问题标题】:Spring Webflux - Chained Mono gets resolved even though the first Mono responds with an Error SignalSpring Webflux - 即使第一个 Mono 响应错误信号,链接的 Mono 也得到解决
【发布时间】:2020-10-14 23:30:25
【问题描述】:

这是我的代码:

public Mono<Foo> doSomething(String fooId, String barId) {

    Mono<Foo> firstResult = firstServiceCall(fooId, barId);
    Mono<List<Baz>> secondResult = secondServiceCall(fooId);

    return firstResult.flatMap(secondResult::thenReturn);
}

private Mono<Foo> firstServiceCall(String fooId, String barId) {
    return fooRepo
            .findByFooIdAndBarId(fooId, barId)
            .switchIfEmpty(Mono.error(new ResponseStatusException(NOT_FOUND)))
            .filter(Foo::isSomething)
            .switchIfEmpty(Mono.error(new ResponseStatusException(UNPROCESSABLE_ENTITY)))
            .doOnNext(foo -> foo.setSomething(false))
            .flatMap(fooRepo::save);
}

private Mono<List<Baz>> secondServiceCall(String fooId) {
    var filter = new BazSearchFilter();
    filter.setFooId(fooId);
    return bazRepo
            .findAllByFilter(filter)
            .doOnNext(baz -> baz.setStatus(BazStatus.SOMETHING))
            .collectList()
            .flatMapMany(bazRepo::saveAll)
            .collectList();
}

由于某种原因,doSomethingMethod 总是调用 secondServiceCall 方法,尽管从 firstServiceCall 方法传播了错误信号(NOT_FOUND 或 UNPROCESSABLE_ENTITY 场景)。

由于我使用的是 flatMap,我希望 secondServiceCall 不会关闭,但也许我遗漏了一些东西。

有谁知道如何解决这个问题?

【问题讨论】:

    标签: java spring spring-webflux reactor


    【解决方案1】:

    你应该重写 doSomething(...) 方法如下:

    public Mono<Foo> doSomething(String fooId, String barId) {
    
        Mono<Foo> firstResult = firstServiceCall(fooId, barId);
    
        return firstResult.doOnNext(foo -> secondServiceCall(fooId));
    }
    

    或如下:

    public Mono<Foo> doSomething(String fooId, String barId) {
    
        Mono<Foo> firstResult = firstServiceCall(fooId, barId);
        Mono<List<Baz>> secondResult = Mono.defer(() -> secondServiceCall(fooId));
    
        return firstResult.flatMap(secondResult::thenReturn);
    }
    

    很有意思的是,这个方法也能按预期工作:

    public Mono<Foo> doSomething(String fooId, String barId) {
    
        Mono<Foo> firstResult = firstServiceCall(fooId, barId);
    
        return firstResult.flatMap(foo -> secondServiceCall(fooId).thenReturn(foo));
    }
    

    绝对是 lambda 可以解决问题

    【讨论】:

    • 有道理!您能否解释一下为什么我的解决方案没有按预期工作?
    • 我认为在您的代码中 Mono&lt;List&lt;Baz&gt;&gt; secondResult 被急切地评估,因为它依赖于 doSomething 方法的 String fooId 参数,而不依赖于 firstServiceCall(...) 的结果,所以第二个service 甚至在 flatMap 转换发生之前就被调用。另见what does Mono.defer() do?
    • 我明白了。我还是 Webflux/Reactor 的新手,所以我不知道延迟。这很有趣。顺便说一句,我用 defer 尝试了你的第二个解决方案,Intellij 突出显示了“defer”这个词,并说该值永远不会用作发布者。尽管我对其进行了测试并且效果很好。这很奇怪:D
    猜你喜欢
    • 1970-01-01
    • 2020-09-18
    • 2020-10-08
    • 2021-11-18
    • 2018-12-12
    • 2021-09-30
    • 2018-09-21
    • 2021-11-09
    • 2011-01-19
    相关资源
    最近更新 更多