RetryInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); int attempts = 0; while (true) { attempts++; try { Response response = chain.proceed(request); int statusCode = response.code(); if (shouldRetry(attempts, statusCode)) { logger.warn(errorCode("HTTP_REQUEST_FAILED"), "http request failed, retry soon, responseStatus={}, uri={}", statusCode, uri(request)); closeRequestBody(response); sleep.sleep(waitTime(attempts)); continue; } return response; } catch (IOException e) { if (shouldRetry(attempts, request.method(), e)) { logger.warn(errorCode("HTTP_REQUEST_FAILED"), "http request failed, retry soon, uri={}, error={}", uri(request), e.getMessage(), e); sleep.sleep(waitTime(attempts)); } else { throw e; } } } } RetryInterceptor(int maxRetries, Duration retryWaitTime, ThreadSleep sleep); @Override Response intercept(Chain chain);  }
@Test void closeResponseIfServiceUnavailable() throws IOException { var request = new Request.Builder().url("http: var source = mock(BufferedSource.class); var serviceUnavailableResponse = new Response.Builder().request(request) .protocol(Protocol.HTTP_2) .code(HTTPStatus.SERVICE_UNAVAILABLE.code) .message("service unavailable") .body(ResponseBody.create(source, MediaType.get("application/json"), 0)) .build(); var okResponse = new Response.Builder().request(request) .protocol(Protocol.HTTP_2) .code(HTTPStatus.OK.code) .message("ok") .build(); var chain = mock(Interceptor.Chain.class); when(chain.request()).thenReturn(request); when(chain.proceed(request)).thenReturn(serviceUnavailableResponse).thenReturn(okResponse); Response response = interceptor.intercept(chain); assertThat(response).isSameAs(okResponse); verify(source).close(); }
@Test void retryWithConnectionFailure() throws IOException { var request = new Request.Builder().url("http: var okResponse = new Response.Builder().request(request) .protocol(Protocol.HTTP_2) .code(HTTPStatus.OK.code) .message("ok") .build(); var chain = mock(Interceptor.Chain.class); when(chain.request()).thenReturn(request); when(chain.proceed(request)).thenThrow(new ConnectException("connection refused")).thenReturn(okResponse); Response response = interceptor.intercept(chain); assertThat(response).isSameAs(okResponse); }
@Test void failedToRetry() throws IOException { var request = new Request.Builder().url("http: var chain = mock(Interceptor.Chain.class); when(chain.request()).thenReturn(request); when(chain.proceed(request)).thenThrow(new ConnectException("connection refused")); assertThatThrownBy(() -> interceptor.intercept(chain)) .isInstanceOf(ConnectException.class) .hasMessageContaining("connection refused"); }