Last active
June 13, 2023 02:50
-
-
Save imminent/ac7f2a222e22f4009af4 to your computer and use it in GitHub Desktop.
Revisions
-
imminent revised this gist
Nov 18, 2015 . 2 changed files with 10 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -119,7 +119,7 @@ public void onFailure(Throwable throwable) { if (mRetries < mMaxRetries) { retryCall(); } else { mDelegate.onFailure(new TimeoutError(throwable)); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,4 +3,13 @@ import java.io.IOException; public class TimeoutError extends IOException { private static final long serialVersionUID = -6469766654369165864L; public TimeoutError() { super(); } public TimeoutError(Throwable cause) { super(cause); } } -
imminent revised this gist
Nov 18, 2015 . 1 changed file with 4 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -18,8 +18,10 @@ * Retries calls marked with {@link Retry}. */ public class RetryCallAdapterFactory implements CallAdapter.Factory { private final ScheduledExecutorService mExecutor; private RetryCallAdapterFactory() { mExecutor = Executors.newScheduledThreadPool(1); } public static RetryCallAdapterFactory create() { @@ -39,7 +41,6 @@ public CallAdapter<?> get(final Type returnType, Annotation[] annotations, Retro final boolean shouldRetryCall = hasRetryAnnotation; final int maxRetries = value; final CallAdapter<?> delegate = retrofit.nextCallAdapter(this, returnType, annotations); return new CallAdapter<Object>() { @Override public Type responseType() { @@ -48,7 +49,7 @@ public Type responseType() { @Override public <R> Object adapt(Call<R> call) { return delegate.adapt(shouldRetryCall ? new RetryingCall<>(call, mExecutor, maxRetries) : call); } }; } -
imminent revised this gist
Nov 18, 2015 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -127,7 +127,7 @@ private void retryCall() { @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); } -
imminent revised this gist
Oct 16, 2015 . 1 changed file with 6 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,6 @@ package com.example.api; import java.io.IOException; public class TimeoutError extends IOException { } -
imminent created this gist
Oct 15, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,19 @@ package com.example.api; import java.util.Map; import retrofit.Call; import retrofit.http.Body; import retrofit.http.GET; import retrofit.http.POST; public interface Api { @Retry(1) @GET("action") Call getAction(); @Retry @POST("action") Call postAction(@Body Map<String, Object> requestBody); } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,18 @@ package com.example.api; import com.squareup.okhttp.OkHttpClient; import retrofit.GsonConverterFactory; import retrofit.Retrofit; public class ApiClient { public final Api api; public ApiClient(OkHttpClient client) { final Retrofit retrofit = new Retrofit.Builder() .addCallAdapterFactory(RetryCallAdapterFactory.create()) .baseUrl("https://api.example.com") .build(); api = retrofit.create(Api.class); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,18 @@ package com.example.api; 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; } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,135 @@ package com.example.api; 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; /** * Retries calls marked with {@link Retry}. */ public class RetryCallAdapterFactory implements CallAdapter.Factory { private RetryCallAdapterFactory() { } 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); final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); 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, executor, 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()); } } private void retryCall() { mExecutor.schedule(new Runnable() { @Override public void run() { final Call<T> call = mCall.clone(); call.enqueue(new RetryingCallback<>(call, mDelegate, mExecutor, mRetries + 1)); } }, (1 << mRetries) * 1000 + random.nextInt(1001), TimeUnit.MILLISECONDS); } } }