001package org.hl7.fhir.r5.utils.client.network;
002
003import okhttp3.Interceptor;
004import okhttp3.Request;
005import okhttp3.Response;
006import javax.annotation.Nonnull;
007
008import java.io.IOException;
009
010/**
011 * An {@link Interceptor} for {@link okhttp3.OkHttpClient} that controls the number of times we retry a to execute a
012 * given request, before reporting a failure. This includes unsuccessful return codes and timeouts.
013 */
014public class RetryInterceptor implements Interceptor {
015
016  // Delay between retying failed requests, in millis
017  private final long RETRY_TIME = 2000;
018
019  // Maximum number of times to retry the request before failing
020  private final int maxRetry;
021
022  // Internal counter for tracking the number of times we've tried this request
023  private int retryCounter = 0;
024
025  public RetryInterceptor(int maxRetry) {
026    this.maxRetry = maxRetry;
027  }
028
029  @Override
030  public Response intercept(Interceptor.Chain chain) throws IOException {
031    Request request = chain.request();
032    Response response = null;
033
034    do {
035      try {
036        // If we are retrying a failed request that failed due to a bad response from the server, we must close it first
037        if (response != null) {
038//          System.out.println("Previous " + chain.request().method() + " attempt returned HTTP<" + (response.code())
039//            + "> from url -> " + chain.request().url() + ".");
040          response.close();
041        }
042        // System.out.println(chain.request().method() + " attempt <" + (retryCounter + 1) + "> to url -> " + chain.request().url());
043        response = chain.proceed(request);
044      } catch (IOException e) {
045        try {
046          // Include a small break in between requests.
047          Thread.sleep(RETRY_TIME);
048        } catch (InterruptedException e1) {
049          System.out.println(chain.request().method() + " to url -> " + chain.request().url() + " interrupted on try <" + retryCounter + ">");
050        }
051      } finally {
052        retryCounter++;
053      }
054    } while ((response == null || !response.isSuccessful()) && (retryCounter <= maxRetry + 1));
055
056    /*
057     * if something has gone wrong, and we are unable to complete the request, we still need to initialize the return
058     * response so we don't get a null pointer exception.
059     */
060    return response != null ? response : chain.proceed(request);
061  }
062
063}