1

Trying to get message from the Gmail using RESTFul API and I'm getting this error : User Rate Limit Exceeded

While, I'm implemented throttling (no more 5 gets in 1 sec, when google says that no more 25 calls in 1 sec) and also exponential backoff when I'm getting any exception and even with all this I'm still getting this exception.

So, what could be the issue here ?

Thanks

SlavaG
  • 518
  • 8
  • 28
  • Include the code that gives you this error? – LeonH Aug 07 '14 at 16:27
  • Is it that you are getting some messages and after some amount of successful retrievals you begin getting the User Rate Limit error? – Arthur Thompson Aug 08 '14 at 17:48
  • @kroikie - Exactly, getting some messages fine and after some time, starting to get rate limit error. – SlavaG Aug 09 '14 at 00:21
  • @Stormie - my code is simple google example, with added exponential backoff in the case of rate limit exception and also sleep of 1 second after 20 messages retrieved (to not get into situation where I call more than 25 times / second). – SlavaG Aug 09 '14 at 00:23
  • How many times have you ran your program, you might've hit the cap for [free API requests](https://developers.google.com/gmail/api/v1/reference/quota)? I can't think of anything else. :( – LeonH Aug 09 '14 at 12:52
  • @Stormie , the program ran number of times, but it didn't get to the limit, used about 3-4$ of daily quota, after I got this exception, number of times, it continue to ran without any exception till the next exception for api usage limit. – SlavaG Aug 10 '14 at 03:30
  • Each operation is not 1 quota unit. Eg retrieving an email costs 5, creating a draft costs 10, deleting a thread costs 20. See https://developers.google.com/gmail/api/v1/reference/quota – Basic Oct 24 '14 at 09:39

1 Answers1

1

There is a well defined quota for Google APIs, here is the one for Gmail: https://developers.google.com/gmail/api/v1/reference/quota#per-method_quota_usage

Here is a small utility class to handle the quota (for single threads, the thread safe implementation is a bit more complex):

public class ApilRateLimiter {

    private long timeSliceEnd;
    private final int quotaPerSecond;
    private int quotaRemaining;

    public ApilRateLimiter(final int quotaPerSecond) {
        this.quotaPerSecond = quotaPerSecond;
        this.quotaRemaining = quotaPerSecond;
        this.timeSliceEnd = System.currentTimeMillis() + 1_000L;
    }

    public void reserve(final int quotaReserved) throws InterruptedException {
        if (quotaReserved > quotaPerSecond) {
            throw new IllegalArgumentException(
                "reservation would never be successful as quota requested is greater than quota per second");
        }           
        final long currentTime = System.currentTimeMillis();
        if (currentTime >= timeSliceEnd) {
            this.timeSliceEnd = currentTime + 1_000L;
            this.quotaRemaining = quotaPerSecond - quotaReserved;
        } else if (quotaReserved <= quotaRemaining) {
            quotaRemaining -= quotaReserved;
        } else {
            Thread.sleep(timeSliceEnd - currentTime);
            reserve(quotaReserved);
        }
    }
}

and the definition for the Gmail quotas:

public interface GmailApiLimits {

    int QUOTA_PER_SECOND = 250;

    int DRAFTS_CREATE = 10;
    int DRAFTS_DELETE = 10;
    int DRAFTS_GET = 5;
    int DRAFTS_LIST = 5;
    int DRAFTS_SEND = 100;
    int DRAFTS_UPDATE = 15;
    int GETPROFILE = 1;
    int HISTORY_LIST = 2;
    int LABELS_CREATE = 5;
    int LABELS_DELETE = 5;
    int LABELS_GET = 1;
    int LABELS_LIST = 1;
    int LABELS_UPDATE = 5;
    int MESSAGES_ATTACHMENTS_GET = 5;
    int MESSAGES_BATCHDELETE = 50;
    int MESSAGES_DELETE = 10;
    int MESSAGES_GET = 5;
    int MESSAGES_IMPORT = 100;
    int MESSAGES_INSERT = 25;
    int MESSAGES_LIST = 5;
    int MESSAGES_MODIFY = 5;
    int MESSAGES_SEND = 100;
    int MESSAGES_TRASH = 5;
    int MESSAGES_UNTRASH = 5;
    int STOP = 50;
    int THREADS_DELETE = 20;
    int THREADS_GET = 10;
    int THREADS_LIST = 10;
    int THREADS_MODIFY = 10;
    int THREADS_TRASH = 10;
    int THREADS_UNTRASH = 10;
    int WATCH = 100;
}

You use it like so:

this.apiRateLimiter = new ApilRateLimiter(GmailApiLimits.QUOTA_PER_SECOND);
...
apiRateLimiter.reserve(GmailApiLimits.MESSAGES_LIST);
gmailApi.users().messages().list("me")...execute();
...
apiRateLimiter.reserve(GmailApiLimits.MESSAGES_GET);
gmailApi.users().messages().get("me"...execute();
...

Basically, you call reserve() before you make a Gmail API call. If there is quota left for the second, reserve returns right away, otherwise it sleeps until the second is over.

Tony BenBrahim
  • 7,040
  • 2
  • 36
  • 49
  • 1
    You can also use the [RateLimiter](https://google.github.io/guava/releases/19.0/api/docs/index.html?com/google/common/util/concurrent/RateLimiter.html) implementation in Guava library. It seems to be a dependency of the google client libraries so should already be on the classpath. – Aman Sep 10 '17 at 09:48