Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I queue up and delay retrofit requests to avoid hitting an api rate limit?

I'm using an api that implements throttling. One of the limits is 1 request/second. ugh. I have the following scenario which hits the limit right away.

  • Check the status of the api with api/status

  • if the api is up, get a users subscriptions

  • load a page from the list of subscriptions

Is there anything I can plug into retrofit that can queue each network request to only run at least 1000ms after the last? I am using/learning rxjava, can debounce be of any use here?

like image 404
Tyler Pfaff Avatar asked Dec 24 '16 00:12

Tyler Pfaff


People also ask

How do you handle a throttling API?

Best practices to handle throttling The following are best practices for handling throttling: Reduce the degree of parallelism. Reduce the frequency of calls. Avoid immediate retries because all requests accrue against your usage limits.

What policy should you apply when you want to limit the access to your API based on levels?

Setting up an API-Level Global Rate Limit Navigate to the API you want to set the global rate limit on. In the Core Settings tab, navigate to the Rate Limiting and Quotas section. Ensure that Disable rate limiting is unchecked. Enter in your request per second threshold.


2 Answers

An interceptor (from OkHttpClient) combined with a RateLimiter (from Guava) is a good solution to avoid HTTP 429 error code.

Let's suppose we want a limit of 3 calls per second:

import java.io.IOException;

import com.google.common.util.concurrent.RateLimiter;

import okhttp3.Interceptor;
import okhttp3.Response;

public class RateLimitInterceptor implements Interceptor {
    private RateLimiter limiter = RateLimiter.create(3);

    @Override
    public Response intercept(Chain chain) throws IOException {
        limiter.acquire(1);
        return chain.proceed(chain.request());
    }
}
like image 53
Italo Borssatto Avatar answered Oct 07 '22 04:10

Italo Borssatto


You can throttle your observable.

    Observable<String> text = ...
text.throttleLast(1, SECONDS)
    .flatMap(retrofitApiCall())
    .subscribe(result -> System.out.println("result: " + result));

Another solution is to set a dispatcher in your okhttp builder, and add an interceptor that sleeps for one second. This may not be the most elegant solution and kills some of the benefits of using async because it limits you to one thread at a time.

OkHttpClient.Builder builder = new OkHttpClient.Builder();


    Dispatcher dispatcher = new Dispatcher();
    dispatcher.setMaxRequests(1);

    Interceptor interceptor = new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            SystemClock.sleep(1000);
            return chain.proceed(chain.request());
        }
    };

    builder.addNetworkInterceptor(interceptor);
    builder.dispatcher(dispatcher);
    builder.build();
like image 43
parkgrrr Avatar answered Oct 07 '22 05:10

parkgrrr