Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.lang.annotation.Documented;
- import java.lang.annotation.Retention;
- import java.lang.annotation.Target;
- import static java.lang.annotation.ElementType.METHOD;
- import static java.lang.annotation.RetentionPolicy.RUNTIME;
- /**
- * Makes the Call retry on failure
- */
- @Documented
- @Target(METHOD)
- @Retention(RUNTIME)
- public @interface Retry {
- int value() default 3;
- }
- //////////////////////////////////////
- import java.io.IOException;
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Type;
- import java.util.Random;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- import retrofit.Call;
- import retrofit.CallAdapter;
- import retrofit.Callback;
- import retrofit.Response;
- import retrofit.Retrofit;
- public class RetryCallAdapterFactory implements CallAdapter.Factory {
- private final ScheduledExecutorService mExecutor;
- private RetryCallAdapterFactory() {
- mExecutor = Executors.newScheduledThreadPool(1);
- }
- public static RetryCallAdapterFactory create() {
- return new RetryCallAdapterFactory();
- }
- @Override
- public CallAdapter<?> get(final Type returnType, Annotation[] annotations, Retrofit retrofit) {
- boolean hasRetryAnnotation = false;
- int value = 0;
- for (Annotation annotation : annotations) {
- if (annotation instanceof Retry) {
- hasRetryAnnotation = true;
- value = ((Retry) annotation).value();
- }
- }
- final boolean shouldRetryCall = hasRetryAnnotation;
- final int maxRetries = value;
- final CallAdapter<?> delegate = retrofit.nextCallAdapter(this, returnType, annotations);
- return new CallAdapter<Object>() {
- @Override
- public Type responseType() {
- return delegate.responseType();
- }
- @Override
- public <R> Object adapt(Call<R> call) {
- return delegate.adapt(shouldRetryCall ? new RetryingCall<>(call, mExecutor, maxRetries) : call);
- }
- };
- }
- static final class RetryingCall<T> implements Call<T> {
- private final Call<T> mDelegate;
- private final ScheduledExecutorService mExecutor;
- private final int mMaxRetries;
- public RetryingCall(Call<T> delegate, ScheduledExecutorService executor, int maxRetries) {
- mDelegate = delegate;
- mExecutor = executor;
- mMaxRetries = maxRetries;
- }
- @Override
- public Response<T> execute() throws IOException {
- return mDelegate.execute();
- }
- @Override
- public void enqueue(Callback<T> callback) {
- mDelegate.enqueue(new RetryingCallback<>(mDelegate, callback, mExecutor, mMaxRetries));
- }
- @Override
- public void cancel() {
- mDelegate.cancel();
- }
- @SuppressWarnings("CloneDoesntCallSuperClone" /* Performing deep clone */)
- @Override
- public Call<T> clone() {
- return new RetryingCall<>(mDelegate.clone(), mExecutor, mMaxRetries);
- }
- }
- // Exponential backoff approach from https://developers.google.com/drive/web/handle-errors
- static final class RetryingCallback<T> implements Callback<T> {
- private static Random random = new Random();
- private final int mMaxRetries;
- private final Call<T> mCall;
- private final Callback<T> mDelegate;
- private final ScheduledExecutorService mExecutor;
- private final int mRetries;
- RetryingCallback(Call<T> call, Callback<T> delegate, ScheduledExecutorService executor, int maxRetries) {
- this(call, delegate, executor, maxRetries, 0);
- }
- RetryingCallback(Call<T> call, Callback<T> delegate, ScheduledExecutorService executor, int maxRetries, int retries) {
- mCall = call;
- mDelegate = delegate;
- mExecutor = executor;
- mMaxRetries = maxRetries;
- mRetries = retries;
- }
- @Override
- public void onResponse(Response<T> response, Retrofit retrofit) {
- mDelegate.onResponse(response, retrofit);
- }
- @Override
- public void onFailure(Throwable throwable) {
- // Retry failed request
- if (mRetries < mMaxRetries) {
- retryCall();
- } else {
- mDelegate.onFailure(new TimeoutError(throwable));
- }
- }
- private void retryCall() {
- mExecutor.schedule(new Runnable() {
- @Override
- public void run() {
- final Call<T> call = mCall.clone();
- call.enqueue(new RetryingCallback<>(call, mDelegate, mExecutor, mMaxRetries, mRetries + 1));
- }
- }, (1 << mRetries) * 1000 + random.nextInt(1001), TimeUnit.MILLISECONDS);
- }
- }
- }
- //////////////////////////////////////////////
- import java.io.IOException;
- public class TimeoutError extends IOException {
- private static final long serialVersionUID = -6469766654369165864L;
- public TimeoutError() {
- super();
- }
- public TimeoutError(Throwable cause) {
- super(cause);
- }
- }
- /////////////////////////////////////////
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement