【问题标题】:How to implement Exponential Backoff for Google Gmail API?如何为 Google Gmail API 实现指数退避?
【发布时间】:2017-12-04 17:25:53
【问题描述】:

我目前正在使用 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。 我可以在哪里设置日志语句以了解是否根据指数策略重试请求?

请推荐

【问题讨论】:

    标签: java gmail-api exponential-backoff


    【解决方案1】:

    我知道这是一个老问题,但会在此处留下我的答案,以防有人发现它有用。

    代码的问题在于它在GoogleCredential.Builder 上调用.setRequestInitializer(),它设置了令牌请求的初始化程序,而不是服务API 请求。

    查看文档here

    将刷新令牌请求的 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();
        }
    

    【讨论】:

      【解决方案2】:

      检查Exponential Backoff 以了解 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 post 以获得更多参考。

      【讨论】:

      • 我在我的代码中提到了上面的指数退避实现。您是否看到该实施有任何问题!我应该自定义更多参数吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      相关资源
      最近更新 更多