繁体   English   中英

如何为 Google Gmail API 实现指数退避?

[英]How to implement Exponential Backoff for Google Gmail API?

我目前正在使用 Gmail API 代表用户发送电子邮件。 邮件是一一发送的,收件人的平均大小为 500。我经常看到{ "code" : 500, "errors" : [ { "domain" : "global", "message" : "Backend Error", "reason" : "backendError" } ], "message" : "Backend Error" }

以及一些发生

{ "code" : 429, "errors" : [ { "domain" : "usageLimits", "message" : "Rate Limit Exceeded", "reason" : "rateLimitExceeded" } ], "message" : "Rate Limit Exceeded" }

Google 建议实施指数退避策略来解决这些错误。 我已经实现了下面的解决方案,但它似乎不起作用并且对这些错误没有帮助。这是我的实现;

public  GoogleCredential createCredentialWithRefreshToken(String accessToken, String refreshToken) 
    {
           GoogleCredential credential =  new GoogleCredential.Builder().setTransport(new NetHttpTransport())
                .setJsonFactory(new JacksonFactory())
                .setClientSecrets(Constants.GOOGLE_CLIENT_ID, Constants.GOOGLE_CLIENT_SECRET)
                .setRequestInitializer(setHttpTimeout())
                .build();
            credential.setAccessToken(accessToken).setRefreshToken(refreshToken);

           return credential;

    }
public HttpRequestInitializer setHttpTimeout() {
          return new HttpRequestInitializer() {

            @Override
            public void initialize(HttpRequest httpRequest) throws IOException {
              httpRequest.setUnsuccessfulResponseHandler(new HttpBackOffUnsuccessfulResponseHandler(backOff()));
              httpRequest.setConnectTimeout(3 * 60000);  // 3 minutes connect timeout
              httpRequest.setReadTimeout(3 * 60000);  // 3 minutes read timeout
            }

            private final ExponentialBackOff.Builder BACK_OFF = new ExponentialBackOff.Builder().setInitialIntervalMillis(500);

            private BackOff backOff() {
               return BACK_OFF.build();
            }   

          };
     }
public static Gmail getGmailServiceForGoogleAccount(GoogleAccount googleAcct){
         Gmail gmailService = null;
        GoogleCredential credential = new Utils().createCredentialWithRefreshToken(googleAcct.getAccess_token(),googleAcct.getRefresh_token());
        gmailService  =   new Gmail.Builder(new NetHttpTransport(),
                                new JacksonFactory(), credential)
                                .setApplicationName("test")
                                .build();

        return gmailService;
     }

这个实现有什么问题? 我是否正确实现了自定义 HttpRequestInitializer。 我可以在哪里设置日志语句以查明是否根据指数策略重试请求?

请建议

我看到这是一个老问题,但我会在这里留下我的答案,以防有人觉得它有用。

与代码的问题是,它调用.setRequestInitializer()GoogleCredential.Builder ,这台令牌的请求,而不是服务API请求初始化。

请参阅此处的文档

为令牌服务器设置刷新令牌请求的 HTTP 请求初始值设定项,或为无设置为 null。

相反,初始化程序应该在 Google 服务客户端上配置,您可以将它与凭据响应处理程序链接起来以保留其功能。

这样的事情应该适用于提供的示例:

    public static HttpRequestInitializer requestInitializer(Credential credential) {
        return new HttpRequestInitializer() {

            @Override
            public void initialize(HttpRequest httpRequest) throws IOException {
                httpRequest.setConnectTimeout(3 * 60000);  // 3 minutes connect timeout
                httpRequest.setReadTimeout(3 * 60000);  // 3 minutes read timeout
                // chain response handler with the handler from the credential
                // that handles retries for authentication errors
                HttpUnsuccessfulResponseHandler responseHandler =
                        new HttpBackOffUnsuccessfulResponseHandler(backOff());
                httpRequest.setUnsuccessfulResponseHandler((req, res, retry) ->
                        credential.handleResponse(req, res, retry)
                                || responseHandler.handleResponse(req, res, retry));
            }

            private final ExponentialBackOff.Builder BACK_OFF = new ExponentialBackOff.Builder().setInitialIntervalMillis(500);

            private BackOff backOff() {
                return BACK_OFF.build();
            }

        };
    }
    public static Gmail getGmailServiceForGoogleAccount(GoogleAccount googleAcct){
        GoogleCredential credential = new Utils().createCredentialWithRefreshToken(googleAcct.getAccess_token(),googleAcct.getRefresh_token());
        return new Gmail.Builder(new NetHttpTransport(), new JacksonFactory(), requestInitializer(credential))
                .setApplicationName("test")
                .build();
    }

检查 Java 实现的指数退避

  ExponentialBackOff backoff = new ExponentialBackOff.Builder()
        .setInitialIntervalMillis(500)
        .setMaxElapsedTimeMillis(900000)
        .setMaxIntervalMillis(6000)
        .setMultiplier(1.5)
        .setRandomizationFactor(0.5)
        .build();
    request.setUnsuccessfulResponseHandler(new HttpBackOffUnsuccessfulResponseHandler(backoff));

检查此SO 帖子以获取更多参考。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM