web-dev-qa-db-ja.com

Spring Webflux / Reactor Netty Webアプリケーション内でブロッキング呼び出しを実行する方法

Reactor NettyでSpring Webfluxマイクロサービスを使用しているユースケースでは、次の依存関係があります。

  • _org.springframework.boot.spring-boot-starter-webflux_(2.0.1.RELEASE)
  • _org.springframework.boot.spring-boot-starter-data-mongodb-reactive_(2.0.1.RELEASE)
  • _org.projectreactor.reactor-spring_(1.0.1.RELEASE)

非常に特定のケースでは、Mongoデータベースからいくつかの情報を取得し、これをリアクティブWebClientで送信するクエリパラメーターに処理する必要があります。 WebClientUriComponentsBuilderもパブリッシャー(Mono/Flux)を受け入れるため、#block()呼び出しを使用して結果を受け取りました。

最新の_reactor-core_(バージョン2.0.1.RELEASE)に含まれている_spring-boot-dependencies_(バージョン0.7.6.RELEASE)以降、使用できないblock()/blockFirst()/blockLast() are blocking, which is not supported in thread xxx、参照-> https://github.com/reactor/reactor-netty/issues/312

私のコードスニペット:

_public Mono<FooBar> getFooBar(Foo foo) {
    MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
    parameters.add("size", foo.getSize());
    parameters.addAll("bars", barReactiveCrudRepository.findAllByIdentifierIn(foo.getBarIdentifiers()) // This obviously returns a Flux
        .map(Bar::toString)
        .collectList()
        .block());

    String url = UriComponentsBuilder.fromHttpUrl("https://base-url/")
        .port(8081)
        .path("/foo-bar")
        .queryParams(parameters)
        .build()
        .toString();

    return webClient.get()
        .uri(url)
        .retrieve()
        .bodyToMono(FooBar.class);
}
_

これは_spring-boot_バージョン2.0.0.RELEASEで機能しましたが、バージョン2.0.1.RELEASEへのアップグレード、したがって_reactor-core_からバージョン0.7.6.RELEASEへのアップグレード以降は許可されません。

私が見る唯一の本当の解決策は、ブロック(非反応)リポジトリ/ mongoクライアントも含めることですが、それが推奨されるかどうかはわかりません。助言がありますか?

6
Dennis Nijssen

WebClientはリクエストURLにPublisherタイプを受け入れませんが、次のことを妨げるものはありません。

public Mono<FooBar> getFooBar(Foo foo) {

    Mono<List<String>> bars = barReactiveCrudRepository
        .findAllByIdentifierIn(foo.getBarIdentifiers())
        .map(Bar::toString)
        .collectList();

    Mono<FooBar> foobar = bars.flatMap(b -> {

        MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
        parameters.add("size", foo.getSize());
        parameters.addAll("bars", b);

        String url = UriComponentsBuilder.fromHttpUrl("https://base-url/")
            .port(8081)
            .path("/foo-bar")
            .queryParams(parameters)
            .build()
            .toString();

        return webClient.get()
            .uri(url)
            .retrieve()
            .bodyToMono(FooBar.class);
    });
    return foobar;         
}

どちらかといえば、この新しいリアクターコアの検査により、WebFluxハンドラーの途中でこのブロック呼び出しを行うことで、アプリケーション全体がクラッシュすることを防ぎました。

4
Brian Clozel