I wrote an article about the two retry mechanisms of HttpClient, but it is not clear whether retries will actually happen as expected.

The apis provided to us were generally fine, and many of the errors did not reproduce consistently, which made it impossible to test thoroughly. It was in this context that WireMock was learned.

This article is not intended to be an introductory tutorial, but to focus on how to solve real-world problems with WireMock. The documentation on the WireMock website is pretty good, so if you want to take a closer look, read it.

Initialize the calling end

First initialize an HttpClient

public ZwroksApi(a){
    RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(1000).build();
    DefaultServiceUnavailableRetryStrategy serviceUnavailableRetryStrategy = new DefaultServiceUnavailableRetryStrategy();
    httpClient = HttpClients.custom()
        .setServiceUnavailableRetryStrategy(serviceUnavailableRetryStrategy)
        .setDefaultRequestConfig(requestConfig)
        .build();
}
Copy the code

The following configuration is performed

  1. Abnormal retry is enabled by default. Retry three times.
  2. If the default service unavailable retry policy is used, the system will retry once at an interval of one second.
  3. Set SocketTimeout to 1 second for simulating timeout.

Abnormal retry

timeout

Set a fixed delay of 2 seconds, so it must time out. As expected, the request will be retried 3 times, so the total is 4 times.

@Test
public void testSocketTimeOut(a) {
    stubFor(get(urlEqualTo("/test"))
            .willReturn(aResponse()
                        .withStatus(HttpStatus.SC_OK)
                        .withHeader("Content-Type"."text/xml")
                        .withBody("ok")
                        .withFixedDelay(2000)));
    zwroksApi.test();
    verify(4, getRequestedFor(urlEqualTo("/test")));
}
Copy the code

But the result

Expected exactly 4 requests matching the following pattern but received 1
Copy the code

The reason, as mentioned in the previous article, is that SocketTimeoutException is a subclass of InterruptedIOException and will not retry.

How to retry a timeout is also described in the previous article, so I won’t repeat it here.

Error return

Several error returns are provided in WireMock and are easy to use

@Test
public void testBadResponse(a) {
    stubFor(get(urlEqualTo("/test"))
            .willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)));
    zwroksApi.test();
    verify(4, getRequestedFor(urlEqualTo("/test")));
}
Copy the code

Here some wrong in the runtime java.net.SocketException: Connection reset, this exception will be retried, so this test can pass.

Service unavailable retry

The code called is as follows, and I want to retry when 503 is returned

@Test
public void testServiceUnavailable(a) {
    stubFor(get(urlEqualTo("/test"))
            .willReturn(aResponse()
                        .withStatus(HttpStatus.SC_SERVICE_UNAVAILABLE)
                        .withHeader("Content-Type"."text/xml")
                        .withBody("service unavailable")));
    zwroksApi.test();
    verify(2, getRequestedFor(urlEqualTo("/test")));
}
Copy the code

Here, too, the test can pass. WireMock provides the ability to get the request log, in addition to the number of times, to see if two requests are one second apart.

    List<ServeEvent> allServeEvents = getAllServeEvents();
    long firstTime = allServeEvents.get(1).getRequest().getLoggedDate().getTime();
    long lastTime = allServeEvents.get(0).getRequest().getLoggedDate().getTime();
    assert lastTime - firstTime > 1000;
Copy the code