package com.boardgamegeek.io; import com.boardgamegeek.io.ExponentialBackOff.Builder; import java.io.IOException; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import timber.log.Timber; public class RetryInterceptor implements Interceptor { private static final int COLLECTION_REQUEST_PROCESSING = 202; private static final int API_RATE_EXCEEDED = 503; private final BackOff backOff202; private final BackOff backOff503; public RetryInterceptor() { super(); backOff202 = new Builder() .setInitialIntervalMillis(1500) .setMultiplier(2.5) .setRandomizationFactor(0.30) .setMaxIntervalMillis(60000) .setMaxElapsedTimeMillis(300000) .build(); backOff503 = new FixedBackOff.Builder() .setIntervalMillis(5000) .setMaxBackOffCount(1) .build(); } @Override public Response intercept(Chain chain) throws IOException { resetBackOff(); Request originalRequest = chain.request(); Response response = chain.proceed(originalRequest); long millis = nextBackOffMillis(response); while (millis != BackOff.STOP) { Timber.d("...sleeping for %,d ms", millis); try { Thread.sleep(millis); } catch (InterruptedException e) { Timber.w(e, "Interrupted while sleeping during retry."); return response; } Timber.d("...retrying"); response = chain.proceed(originalRequest); millis = nextBackOffMillis(response); } return response; } private void resetBackOff() { backOff202.reset(); backOff503.reset(); } private long nextBackOffMillis(Response response) { if (response.code() == COLLECTION_REQUEST_PROCESSING) { return backOff202.nextBackOffMillis(); } else if (response.code() == API_RATE_EXCEEDED) { return backOff503.nextBackOffMillis(); } return BackOff.STOP; } }