1. ホーム
  2. java

[解決済み] WebClientで例外処理 io.netty.handler.timeout.ReadTimeoutException を投げる

2022-02-09 22:07:05

質問

私はリアクティブ・プログラミングの初心者で、テストしたいコードをいくつか書きました。私はファイルをライブでコピーして、それらが同じであるかどうかを後でチェックするので、それらはより統合的なテストです。私は MockWebServer をモックにしたものです。 4xx これは、コード内でうまく処理されています。残念ながら、私は io.netty.handler.timeout.ReadTimeoutException これは、私のカスタム WebClientResponseException ので、テストでは間違った例外が発生します。基本的には2つの疑問があります。 io.netty.handler.timeout.ReadTimeoutException 例外が発生します。の後にのみ表示されます。 doOnError() メソッドで、なぜこのようなことが起こっているのかさえ、よくわかりません。

今現在のコードがそうであり、同期的であることは十分承知しています。

2つ目の質問は、与えられた再試行回数の後、テストの中でどのようにカスタム例外を処理できるかということです。今は3回で、その時だけ別の例外をスローするようにしたいのです。

以下はそのコードです。

AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(targetPath, StandardOpenOption.WRITE);

Flux<DataBuffer> fileDataStream = Mono.just(filePath)
    .map(file -> targetPath.toFile().exists() ? targetPath.toFile().length() : 0)
    .map(bytes -> webClient
                  .get()
                  .uri(uri)
                  .accept(MediaType.APPLICATION_OCTET_STREAM)
                  .header("Range", String.format("bytes=%d-", bytes))
                  .retrieve()
                  .onStatus(HttpStatus::is4xxClientError, clientResponse -> Mono.error(new CustomException("4xx error")))
                  .onStatus(HttpStatus::is5xxServerError, clientResponse -> Mono.error(new CustomException("5xx error")))
                  .bodyToFlux(DataBuffer.class)
                  .doOnError(throwable -> log.info("fileDataStream  onError", throwable))
                )
    .flatMapMany(Function.identity());

return DataBufferUtils
        .write(fileDataStream, fileChannel)
        .map(DataBufferUtils::release)
        .doOnError(throwable -> {
            try {
                fileChannel.force(true);
            } catch (IOException e) {
                throw new WritingException("failed force update to file channel", e);
            }
        })
        .retry(3)
        .doOnComplete(() -> {
             try {
                 fileChannel.force(true);
             } catch (IOException e) {
                 log.warn("failed force update to file channel", e);
                 throw new WritingException("failed force update to file channel", e);
             }
        })
        .doOnError(throwable -> targetPath.toFile().delete())
        .then(Mono.just(target));

レスポンスは Mono<Path> にしか興味がないので Path 新しく作成されコピーされたファイルの

コードに関するコメントをお待ちしています。

コピー機構は、このスレッドを参考にして作りました。 Project ReactorでExchangeFunctionを使ってClientRequestからファイルをダウンロードし、保存する。

どのように解決するのですか?

つまり、基本的にはテストに問題があったということです。私は MockResponse にエンキューされます。 MockWebServer で再試行すると、一度だけ WebClient 模擬サーバには何もレスポンスが設定されていませんでした(基本的に模擬レスポンスがないため、全く利用できないような挙動となりました)。

サーバーが完全にダウンした場合の例外処理に対応するために、次のような行をフラックスチェーンに追加する価値があると私は考えています。

.doOnError(ChannelException.class, e -> {
    throw new YourCustomExceptionForHandlingServerIsDownSituation("Server is unreachable", e);
})

これを利用すると ReadTimeoutException を拡張しているため、Nettyから(サーバーに到達できない場合)。 ChannelException クラスがあります。例外処理は必ず行ってください。