问题描述
尝试使用RESTFul API从Gmail中获取邮件,但出现此错误:超出用户速率限制
Trying to get message from the Gmail using RESTFul API and I'm getting this error :User Rate Limit Exceeded
同时,我实现了节流(当Google说在1秒钟内不再有25个调用时,在1秒钟内不会再有5个),并且在遇到任何异常甚至我遇到的所有情况时,也会实现指数回退仍然得到这个例外.
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 ?
谢谢
推荐答案
Google API有一个明确定义的配额,这是Gmail的配额: https://developers.google.com/gmail/api/v1/reference/quota#per-method_quota_usage
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);
}
}
}
以及Gmail配额的定义:
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;
}
您可以像这样使用它:
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();
...
基本上,您在调用Gmail API之前先调用reserve()
.如果第二秒有剩余配额,储备金将立即返还,否则它将一直休眠直到第二秒结束.
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.
这篇关于Gmail API Users.Messages.get引发超出用户速率限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!