Search code examples
javagmail-apigoogle-api-java-client

Gmail Javi API batch too many requests


I am using the Java Gmail API to retrieve some email messages. Once I get a list of messages, I am using batching to get the individual messages info.

Sample code as follows:

 List<MessageDto> messages = new ArrayList<>();
    String nextPageToken = null;

    List<Message> batchMessages = new ArrayList<Message>();
    ListMessagesResponse response =
            gmailClient(googleId)
                    .users()
                    .messages()
                    .list(googleId)
                    .setQ(query)
                    .setPageToken(pageToken)
                    .setMaxResults(maxResults == null ? 50 : maxResults)
                    .execute();

    if (response.getMessages() != null) {
        batchMessages.addAll(response.getMessages());
        nextPageToken = response.getNextPageToken();

        final JsonBatchCallback<Message> callback =
                new JsonBatchCallback<Message>() {
                    public void onSuccess(Message message, HttpHeaders responseHeaders) {
                        messages.add(MessageMapper.getMessage(googleId, message, false));
                    }

                    public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
                        log.error("Could not process message ", e);
                     
                    }
                };
        BatchRequest batch = gmailClient(googleId).batch();
           

        for (Message message : batchMessages) {
            gmailClient(googleId)
                    .users()
                    .messages()
                    .get(googleId, message.getId())
                    .setFormat("raw")
                    .queue(batch, callback);
        }
        batch.execute();
    }

The problem I am having is that not all the batch messages are retrieved due to too many requests and falling into the onFailure method.

I tried setting a HttpBackOffUnsuccessfulResponseHandler on the HttpRequestInitializer but that did not work.

I stumbled upon on this in the documentation: https://cloud.google.com/java/docs/reference/google-api-client/latest/com.google.api.client.googleapis.batch

There is a note saying:

Note: When setting an HttpUnsuccessfulResponseHandler by calling to HttpRequest#setUnsuccessfulResponseHandler, the handler is called for each unsuccessful part. As a result it's not recommended to use HttpBackOffUnsuccessfulResponseHandler on a batch request, since the back-off policy is invoked for each unsuccessful part.

Is there anyway how I can handle the too many requests exception and retry the request?

Any help would be much appreciated.


Solution

  • batching doesn't save you anything except the http call its still going to cost the same to your quota.

    When you send a batch of say 50 requests (it depends on the api how many you can send in a batch) all of those requests hit the server at the same time and are run. This means that batching can result in many flooding type errors which i think you are seeing. You wont always get them because if the server you land on is busy then it may take it time to process your requests. However if you manage to land on a server that is not busy they could all run in record time and you will then get an error saying your flooding.

    The recommendations i normally give my clients are.

    1. don't bother batching.
    2. If you really must batch keep the number low try 10 if you still get errors try

    If you do get errors its hard to know which ones were sent and which errored out in the batch on some apis. You will need to configure a system to check if the change was made and if not then send it in the next batch. This alone is why i recommend not batching.