GMail API随机返回未确认的错误

时间:2015-06-29 06:58:23

标签: python google-app-engine gmail-api

我在Google App Engine上运行Python应用程序,该应用程序定期检查多个用户的最新电子邮件。我注意到,在随机时刻,API会返回以下错误:

error: An error occured while connecting to the server: Unable to fetch URL: https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest?userIp=0.1.0.2

通常情况下,如果作业再次运行,则可以正常运行。在我的代码下面。我想了解导致这种情况的原因,更重要的是我如何防止错误阻止进程(例如,在抛出此错误时如何使用相同的值再次运行作业)。

class getLatest(webapp2.RequestHandler):
  def post(self):
    try:
      email = self.request.get('email')
      g = Credentials.get_by_id(email)
      REFRESH_TOKEN = g.refresh_token
      start_history_id = g.hid

      credentials = OAuth2Credentials(None, settings.CLIENT_ID,
                             settings.CLIENT_SECRET, REFRESH_TOKEN, None,
                             GOOGLE_TOKEN_URI, None,
                             revoke_uri=GOOGLE_REVOKE_URI,
                             id_token=None,
                             token_response=None)

      http = credentials.authorize(httplib2.Http())
      service = discovery.build("gmail", "v1", http=http)
      for n in range(0, 5): 
        try:
          history = service.users().history().list(userId=email, startHistoryId=start_history_id).execute(http=http)
          break
        except errors.HttpError, e:
          if n < 4:
            time.sleep((2 ** n) + random.randint(0, 1000) / 1000)
          else:
            raise
      changes = history['history'] if 'history' in history else []
      while 'nextPageToken' in history:
        page_token = history['nextPageToken']
        for n in range(0, 5): 
          try:
            history = service.users().history().list(userId=email, startHistoryId=start_history_id, pageToken=page_token).execute(http=http)
            break
          except errors.HttpError, e:
            if n < 4:
              time.sleep((2 ** n) + random.randint(0, 1000) / 1000)
            else:
              raise
        changes.extend(history['history'])

    except errors.HttpError, error:
        logging.exception('An error occurred: '+str(error))
        if error.resp.status == 401:
            # Credentials have been revoked.
            # TODO: Redirect the user to the authorization URL.
            raise NotImplementedError()
        else:
            stacktrace = traceback.format_exc()
            logging.exception('%s', stacktrace)

更新

我根据下面的答案更新了代码,但它似乎永远不会多次运行请求。一旦发生异常,该过程就会中止。

2 个答案:

答案 0 :(得分:0)

由于多种原因可能会发生此错误,包括您的代理离线一段时间超过Gmail API的速率限制。您需要以优雅的方式重试这些临时问题。以下是可能有用的代码编辑:

class getLatest(webapp2.RequestHandler):
  def post(self):

try:
  email = self.request.get('email')
  g = Credentials.get_by_id(email)
  REFRESH_TOKEN = g.refresh_token
  start_history_id = g.hid

  credentials = OAuth2Credentials(None, settings.CLIENT_ID,
                         settings.CLIENT_SECRET, REFRESH_TOKEN, None,
                         GOOGLE_TOKEN_URI, None,
                         revoke_uri=GOOGLE_REVOKE_URI,
                         id_token=None,
                         token_response=None)

  http = credentials.authorize(httplib2.Http())
  service = discovery.build("gmail", "v1", http=http)
  for n in range(0, 5):  
  try:
      history = service.users().history().list(userId=email, startHistoryId=start_history_id).execute(http=http)
      break
  except Exception as e:
        # Apply exponential backoff.
        time.sleep((2 ** n) + random.randint(0, 1000) / 1000)

  changes = history['history'] if 'history' in history else []
  while 'nextPageToken' in history:
    page_token = history['nextPageToken']

    for n in range(0, 5):  
    try:
       history = service.users().history().list(userId=email, startHistoryId=start_history_id, pageToken=page_token).execute(http=http)
       changes.extend(history['history'])
       break
    except Exception as e:
        # Apply exponential backoff.
        time.sleep((2 ** n) + random.randint(0, 1000) / 1000)
except errors.HttpError, error:
    logging.exception('An error occurred: '+str(error))
    if error.resp.status == 401:
        # Credentials have been revoked.
        # TODO: Redirect the user to the authorization URL.
        raise NotImplementedError()
    else:
        stacktrace = traceback.format_exc()
        logging.exception('%s', stacktrace)

基本上,如果谷歌从具有指数退避的相同点发生异常,则此代码将重试。添加您要重试的错误代码。希望这可以解决您的问题。

答案 1 :(得分:0)

事实证明这与报道here的问题相同。我在请求发现文档时达到了速率限制,您每天只需要执行一次。我通过在我的应用上实施建议的解决方案来解决它。代码可以在this Stackoverflow question

中找到