GMail API returns 随机出现不明错误
GMail API returns unspeficied error at random moments
我正在 运行在 Google App Engine 上安装一个 Python 应用程序,它会定期检查多个用户的最新电子邮件。我注意到在随机时刻,API returns 出现以下错误:
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)
更新
我根据下面的答案更新了代码,但它似乎从未多次 运行 请求。一旦发生异常,进程就会中止。
出现此错误的原因有多种,包括您的代理暂时脱机到超过 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)
本质上,如果异常发生在 google 结束时,此代码会从具有指数退避的同一点开始重试。添加您要重试的错误代码。希望这能解决您的问题。
事实证明这与报告的问题相同 here. I was hitting the rate limit on requesting the discovery document, which you only need to do once per day. I solved it by implementing the suggested solution on my app. The code can be found in 。
我正在 运行在 Google App Engine 上安装一个 Python 应用程序,它会定期检查多个用户的最新电子邮件。我注意到在随机时刻,API returns 出现以下错误:
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)
更新
我根据下面的答案更新了代码,但它似乎从未多次 运行 请求。一旦发生异常,进程就会中止。
出现此错误的原因有多种,包括您的代理暂时脱机到超过 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)
本质上,如果异常发生在 google 结束时,此代码会从具有指数退避的同一点开始重试。添加您要重试的错误代码。希望这能解决您的问题。
事实证明这与报告的问题相同 here. I was hitting the rate limit on requesting the discovery document, which you only need to do once per day. I solved it by implementing the suggested solution on my app. The code can be found in