【问题标题】:How to test Spring WebClient retry when?如何测试 Spring WebClient 何时重试?
【发布时间】:2020-01-17 10:22:22
【问题描述】:

我需要实现以下行为:

  • 发出 REST 发布请求
  • 如果响应返回状态为 429 Too many requests,则最多重试 3 次,延迟 1 秒
  • 如果第三次重试失败或发生任何其他错误,请记录并将内容写入数据库
  • 如果请求成功(http 状态 200),记录一些信息

我想为此目的使用 Spring WebClient 并想出了以下代码:

Mono<ClientResponse> response = webClient.post()
            .uri(URI.create("/myuri"))
            .body(BodyInserters.fromObject(request))
            .retrieve()
            .onStatus(httpStatus -> httpStatus.equals(HttpStatus.TOO_MANY_REQUESTS), 
                      response -> Mono.error(new TooManyRequestsException("System is overloaded")))
            .bodyToMono(ClientResponse.class)
            .retryWhen(Retry.anyOf(TooManyRequestsException.class)
                                          .fixedBackoff(Duration.ofSeconds(1)).retryMax(3))
            .doOnError(throwable -> saveToDB(some_id, throwable))
            .subscribe(response -> logResponse(some_id, response));

现在我想测试重试机制和错误处理是否按预期工作。也许我可以为此目的使用StepVerifier,但我只是不知道如何在我的情况下使用它。有什么有用的提示吗?

【问题讨论】:

    标签: rx-java reactive-programming project-reactor spring-webclient


    【解决方案1】:

    我认为您可以使用模拟网络服务器来测试它,例如MockWebServer.

    @Test
    public void testReactiveWebClient() throws IOException
    {
        MockWebServer mockWebServer = new MockWebServer();
    
        String expectedResponse = "expect that it works";
        mockWebServer.enqueue(new MockResponse().setResponseCode(429));
        mockWebServer.enqueue(new MockResponse().setResponseCode(429));
        mockWebServer.enqueue(new MockResponse().setResponseCode(429));
        mockWebServer.enqueue(new MockResponse().setResponseCode(200)
                                      .setBody(expectedResponse));
    
        mockWebServer.start();
    
        HttpUrl url = mockWebServer.url("/mvuri");
        WebClient webClient = WebClient.create();
    
        Mono<String> responseMono = webClient.post()
                .uri(url.uri())
                .body(BodyInserters.fromObject("myRequest"))
                .retrieve()
                .onStatus(
                        httpStatus -> httpStatus.equals(HttpStatus.TOO_MANY_REQUESTS),
                        response -> Mono.error(new TestStuff.TooManyRequestsException("System is overloaded")))
                .bodyToMono(String.class)
                .retryWhen(Retry.anyOf(TestStuff.TooManyRequestsException.class)
                                   .fixedBackoff(Duration.ofSeconds(1)).retryMax(3));
    
        StepVerifier.create(responseMono)
                .expectNext(expectedResponse)
                .expectComplete().verify();
    
        mockWebServer.shutdown();
    }
    

    如果您使用状态码 429 将另一个 MockResponse 排入队列,则验证将失败,与 e.g. 相同。错误代码500

    【讨论】:

      【解决方案2】:

      Dominik Sandjaja 的回答基本上帮助我设置了我的测试。为了完整起见,我在这里发布了工作版本:

      @Test
      public void mytest() {
          MockResponse mockResponse = new MockResponse()
              .setHeader(HttpHeaders.CONTENT_TYPE, "application/json")
              .setResponseCode(429).setBody("Too many requests");
          mockWebServer.enqueue(mockResponse);
          mockWebServer.enqueue(mockResponse);
          mockWebServer.enqueue(mockResponse);
          mockWebServer.enqueue(mockResponse);
      
          Mono<MyClass> responseMono = methodDoingTheAsyncCall.sendAsync(...);
          StepVerifier.create(responseMono)
                      .expectError(RetryExhaustedException.class)
                      .verify();
      }
      

      【讨论】:

        猜你喜欢
        • 2020-01-21
        • 1970-01-01
        • 2020-04-11
        • 1970-01-01
        • 2021-01-28
        • 2021-11-03
        • 2021-04-20
        • 1970-01-01
        • 2021-06-13
        相关资源
        最近更新 更多