Gmail API socket.timeout : 读取操作超时

问题描述

我使用 Python Gmail API 的程序遇到了很多 socket.timeout 错误。我经常收到以下信息:

socket.timeout: The read operation timed out

错误似乎是随机的,通常出现在任何 Gmail API 函数中。我尝试修改套接字超时参数。但是,更改此参数似乎并没有消除问题。我已经将它从 1 秒、10 秒和 600 秒变化了。

socket.setdefaulttimeout(10)

或者对于 httplib2.Http 对象:

def build_http(self): 
    """Builds httplib2.Http object 

    Returns: 
    A httplib2.Http object,which is used to make http requests,and which has timeout set by default. 
    To override default timeout call 

        socket.setdefaulttimeout(timeout_in_sec) 

    before interacting with this method. 
    """ 
    try: 
        return httplib2.Http(timeout=10) 
    except: 
        self.GLogger.error("An error was encountered in build_http")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

以下代码用于初始化 Gmail API 服务。

def gmailAPIInitialize(self):
    try:
        self.waitForInternet()
        self.GLogger.info("Initializing the Gmail API Service")
        creds = None
        # The file token.pickle stores the user's access and refresh tokens,and is
        # created automatically when the authorization flow completes for the first
        # time.
        if self.reprocess is True: 
            token_pickle_file = 'Gmail_token_2.pickle'
            credentials_file = 'Gmail_credentials_2.json'
        else:
            token_pickle_file = 'Gmail_token_1.pickle'
            credentials_file = 'Gmail_credentials_1.json'
            
        if os.path.exists(token_pickle_file):
            with open(token_pickle_file,'rb') as token:
                creds = pickle.load(token)
        # If there are no (valid) credentials available,let the user log in.
        if not creds or not creds.valid:
            if creds and creds.expired and creds.refresh_token:
                creds.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    credentials_file,ScopES)
                creds = flow.run_local_server(port=0)
            # Save the credentials for the next run
            with open(token_pickle_file,'wb') as token:
                pickle.dump(creds,token)
   
        #service = build('gmail','v1',credentials=creds,cache_discovery=False)
        service = build('gmail',cache_discovery=False)
        self.gmailAPIService  = service
        self.GLogger.info("Successfully initialized the Gmail API Service")
        return True
    except:
        self.GLogger.error("An error was encountered while attempting to initialize the Gmail API")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

同样,几乎任何函数都会触发这个问题。但这里有一些例子:

主题列表:

def gmailAPIMessageLabelSearchThreads(self,labelList,userID="me",allPages=False,reverSEOrder=False):
    try:
        self.GLogger.info("Attempting to search email threads with labelList (" + str(labelList)+ ") and userID (" +str(userID)+ ")")
        service = self.gmailAPIService
        if service is None:
            logging.error('Gmail Service not initialized')
            return False
        response = service.users().threads().list(userId=userID,labelIds=labelList,maxResults=500,fields="threads(id),nextPagetoken").execute()
        messages = []
        if 'messages' in response:
            messages.extend(response['messages'])
        if (allPages is True):     
            while 'nextPagetoken' in response:
                page_token = response['nextPagetoken']
                response = service.users().messages().list(userId=userID,pagetoken=page_token,nextPagetoken").execute()
                if 'messages' in response:
                    messages.extend(response['messages'])

        if reverSEOrder is True: 
            messages.reverse()

        self.GLogger.info("Successfully searched emails with labelList (" + str(labelList)+ ") and userID (" +str(userID)+ "). Number of matching emails (" +str(len(messages))+ ")")

        return messages
    except:
        self.GLogger.error("An error was encounrtered while searching for messages with Google Api and label list")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

发送电子邮件

def gmailAPISendEmail(self,message,userID="me"):
    try:
        service = self.gmailAPIService
        self.GLogger.info("Attempting to send email message")
        response = (service.users().messages().send(userId=userID,body=message).execute())
        responseID = str(response['id'])
        self.GLogger.info("Successfully sent email message with ID (" + responseID +")")
        return responseID
    except:
        self.GLogger.error("Failed to send email message")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

消息列表:

def gmailAPIMessageLabelSearch(self,reverSEOrder=False,numPages=None):
    try:
        self.GLogger.info("Attempting to search emails with labelList (" + str(labelList)+ ") and userID (" +str(userID)+ ")")
        service = self.gmailAPIService
        if service is None:
            logging.error('Gmail Service not initialized')
            return False
        #response = service.users().messages().list(userId=userID,fields='messages(id)').execute()
        response = service.users().messages().list(userId=userID,fields="messages(id),nextPagetoken").execute()
        messages = []
        if 'messages' in response:
            messages.extend(response['messages'])
        numPages_Processed = 0
        if (allPages is True):     
            while 'nextPagetoken' in response:
                page_token = response['nextPagetoken']
                #response = service.users().messages().list(userId=userID,fields='messages(id)',maxResults=500).execute()
                response = service.users().messages().list(userId=userID,nextPagetoken").execute()
                if 'messages' in response:
                    messages.extend(response['messages'])
                    numPages_Processed = numPages_Processed + 1
                if (numPages is not None) and numPages_Processed>=numPages:
                    break


        if reverSEOrder is True: 
            messages.reverse()

        self.GLogger.info("Successfully searched emails with labelList (" + str(labelList)+ ") and userID (" +str(userID)+ "). Number of matching emails (" +str(len(messages))+ ")")
        listToReturn = list()
        for message in messages:
            listToReturn.append(message['id'])
        return listToReturn
    except:
        self.GLogger.error("An error was encounrtered while searching for messages with Google Api and label list")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

附件下载:

def gmailAPIDownloadAttachments(self,messageID,message=None,userID="me"):
    try:
        service = self.gmailAPIService
        self.GLogger.info("Attempting to download attachments from messageID (" +str(messageID)+ ")")
        if message is None: 
            message = self.gmailAPIGetFullMessage(messageID,userID=userID)
            if message is False:
                self.GLogger.error("Failed to extract message (" +str(messageID)+ ") for downloading attachments")
                return False
        attachmentList = list()
        payload = message['payload']
        if 'parts' in payload:
            parts = payload['parts']
            for part in parts:
                if part['filename']:
                    if 'data' in part['body']:
                        data = part['body']['data']
                    else:
                        att_id = part['body']['attachmentId']
                        att = service.users().messages().attachments().get(userId=userID,messageId=messageID,id=att_id).execute()
                        data = att['data']
                    file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
                    filename = part['filename']
                    extSearch = filename.find('.')
                    if extSearch == -1:
                        ext = ""
                        partFileName = filename[0:extSearch]
                    else:
                        ext = filename[extSearch+1:]
                        partFileName = filename[0:extSearch]

                    theAttachment = Attachment(filename,partFileName,ext,file_data)
                    attachmentList.append(theAttachment)

        self.GLogger.info("Successfully downloaded attachments from messageID (" +str(messageID)+ ")")
        return(attachmentList)
    except:
        self.GLogger.error("Encountered an error while attempting to download email attacments from messageID (" +str(messageID)+ ")")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

Batch Requests,其中 searchResultParts 是一个列表列表,其中每个嵌入的列表包含 100 个消息 ID:

for searchResultPart in searchResultParts: 
    batch = service.new_batch_HTTP_Request(callback=self.theEmailCallback)
    for msgiD in searchResultPart: #Loop through each messageID
        request1 = service.users().messages().get(userId=userID,id=msgiD)
        batch.add(request=request1,request_id=msgiD) 
    batch.execute(http=self.http_toUse) 

我使用了多个 Python Gmail API 函数,这些只是其中的一个子集。但是,所有这些都倾向于在某个时候产生 socket.timeout 错误。目前,我的防火墙已关闭(ufw 处于非活动状态)。

我相信我正在按预期使用这些功能,并且相信这个问题出在 Google 身上。是否有谷歌团队成员可以对此进行调查?我能做些什么来解决这个问题?这些 socket.timeout 错误经常发生,导致我的应用程序出现问题。

我的互联网连接是千兆光纤,用于上传和下载。

编辑** 我现在通过这个函数调用我所有的 Python Gmail API 请求。它将等待 50 毫秒(然后每次重试多 50 毫秒),然后重试直到请求成功或直到进行了 10 次重试。 socket.timeout 错误仍然很普遍,但根据我目前的观察,似乎大多数 socket.timeout 错误会在 2 或 3 次重试后发生。

def executeGmailAPI_withretry(self,request):
    try: 
        response_valid = False
        num_retries = 0
        while num_retries < 10: 
            try: 
                response = request.execute()
                response_valid = True
                break
            except socket.timeout:
                num_retries = num_retries + 1 
                time.sleep(0.05*num_retries)
            except: 
                self.GLogger.error("An error was encounrtered in executeGmailAPI_withretry")
                tb = traceback.format_exc()
                self.GLogger.exception(tb)
                num_retries = num_retries + 1 
                time.sleep(0.05*num_retries)

        if response_valid is False: 
            return False
        else: 
            return response
    except: 
        self.GLogger.error("An error was encounrtered in executeGmailAPI_withretry")
        tb = traceback.format_exc()
        self.GLogger.exception(tb)
        return False

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)