RESTFul API を使用して Gmail からメッセージを取得しようとすると、次のエラーが表示されます: User Rate Limit Exceeded
一方、私はスロットリングを実装しています(Googleが1秒間に25回以上の呼び出しはないと言っている場合、1秒間に5回以上取得することはありません)。例外。
では、ここで何が問題になるのでしょうか?
ありがとう
RESTFul API を使用して Gmail からメッセージを取得しようとすると、次のエラーが表示されます: User Rate Limit Exceeded
一方、私はスロットリングを実装しています(Googleが1秒間に25回以上の呼び出しはないと言っている場合、1秒間に5回以上取得することはありません)。例外。
では、ここで何が問題になるのでしょうか?
ありがとう
Google API には明確に定義された割り当てがあります。Gmail の割り当ては次のとおりです: https://developers.google.com/gmail/api/v1/reference/quota#per-method_quota_usage
クォータを処理するための小さなユーティリティ クラスを次に示します (シングル スレッドの場合、スレッド セーフな実装はもう少し複雑です)。
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 クォータの定義:
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();
...
基本的にreserve()
、Gmail API 呼び出しを行う前に呼び出します。2 番目のクォータが残っている場合、reserve はすぐに戻ります。それ以外の場合は、2 番目が終了するまでスリープします。