如何在Spring WebClient中捕获超时异常?

huangapple go评论72阅读模式
英文:

How to catch timeout exception in Spring WebClient?

问题

私下我正在编写一个方法,使用WebClient发送POST请求到另一个服务。

private Mono<GameEntity> callApplication(GameEntity gameEntity) throws URISyntaxException {
    WebClient client = WebClient.create();
    for(int i=0; i<NUM_OF_RETRY; ++i) {
        String port = strategy.getNextInstancePort();
        URI uri = new URI(String.format("http://localhost:%s/game/add", port));
        try {
            Mono<GameEntity> response = client.post()
                    .uri(uri)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(Mono.just(gameEntity), GameEntity.class)
                    .retrieve()
                    .bodyToMono(GameEntity.class)
                    .timeout(Duration.ofSeconds(3));
            return response;
        } catch (WebClientRequestException e) {
            //....
        } catch (Exception e) {
            strategy.incrErrorCount(port);
        }
    }
    return null;
}

我的方法是,当超时发生时,我们需要调用另一个方法 strategy.incrErrorCount(port)。但是WebClient不会抛出任何可以在 catch (Exception e) 块中捕获的异常。

在超时发生时,是否有任何解决方案来访问这个方法?

英文:

Currently I am writing a method that using WebClient to send POST request to another service.

  private Mono&lt;GameEntity&gt; callApplication(GameEntity gameEntity) throws URISyntaxException {
    WebClient client = WebClient.create();
    for(int i=0;i&lt;NUM_OF_RETRY;++i) {
        String port = strategy.getNextInstancePort();
        URI uri = new URI(String.format(&quot;http://localhost:%s/game/add&quot;, port));
        try {
            Mono&lt;GameEntity&gt; response = client.post()
                    .uri(uri)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(Mono.just(gameEntity), GameEntity.class)
                    .retrieve()
                    .bodyToMono(GameEntity.class)
                    .timeout(Duration.ofSeconds(3))
            return response;
        } catch (WebClientRequestException e) {
            //....
        } catch (Exception e) {
            strategy.incrErrorCount(port);
        }
    }
    return null;
}

My approach is when the timeout occurs, we need to call another method strategy.incrErrorCount(port). But the webclient does not throw any exception that can be caught in catch (Exception e) block.

Is there any solution to access this method when timeout occurs?

答案1

得分: 1

如果你指的是由于以下代码而发生的超时:

.timeout(Duration.ofSeconds(3))

那么 timeout() 操作符还有另一种签名:

public final Mono<T> timeout(Duration timeout, Mono<? extends T> fallback)

根据 Java 文档的描述:

如果在给定的持续时间内没有收到任何项目,则切换到备用的 Mono。如果备用的 Mono 为 null,则抛出 TimeoutException。

因此,你可以将 strategy.incrErrorCount(port) 传递给该方法,那么该行代码将如下所示:

.timeout(Duration.ofSeconds(3), Mono.fromSupplier(() -> strategy.incrErrorCount(port)))
英文:

If you mean the timeout that happens due to

.timeout(Duration.ofSeconds(3))

Then timeout() operator has another signature

public final Mono&lt;T&gt; timeout(Duration timeout, Mono&lt;? extends T&gt; fallback)

From java doc:

> Switch to a fallback Mono in case no item arrives within the given
> Duration. If the fallback Mono is null, signal a TimeoutException
> instead.

So, you can pass your strategy.incrErrorCount(port) into that method, so that line would look like this:

.timeout(Duration.ofSeconds(3), Mono.fromSupplier(() -&gt; strategy.incrErrorCount(port)))

huangapple
  • 本文由 发表于 2023年5月28日 22:09:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76351901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定