You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用google-api-python-client连接Google Drive时随机超时问题求助

树莓派Google Drive定时上传超时问题排查

我用树莓派做了个定时项目,每小时拍摄照片并上传到Google Drive。用google-api-python-client对接Drive API,apscheduler后台自动执行流程。流程大概80%时间能正常跑,但有20%概率会触发Timeout错误。

我已经给服务对象加了5次重试机制,把超时等待时间调到3分钟,问题还是没解决。现在停了自动化流程,用下面的open()函数手动连接,依然出现相同的超时问题,而且当前网络是正常的。

奇怪的是,流程会连续几小时正常运行,然后突然进入一段超时期,之后又自动恢复正常。我查了Drive API配额,远没到限制。想问问是不是有过期的配置项?或者无意中消耗了什么受限资源?附上相关代码和错误日志,求帮忙排查。

相关代码

import os
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from error_logger import ErrorLogger
from ssl import SSLCertVerificationError
import socket

SCOPES = ['https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = "API_KEYS/my_credentials.json"

credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
connected = False
timeout_in_sec = 60*3

def open():
    try:
        global connected
        socket.setdefaulttimeout(timeout_in_sec)
        service =  build('drive', 'v3', credentials=credentials)
        service.files().list(pageSize=1, fields="files(id, name)").execute()
        socket.setdefaulttimeout(None)
        connected = True
        return service
    except Exception as e:
        ErrorLogger.log(e)

def close(service):
    global connected
    connected = False
    service.close()

service = open()
close(service)

错误日志

2025-03-29 15:00:02,425 - my_application - ERROR - timed out Traceback
(most recent call last): File
"/home/pablo/Desktop/estacion_captura/gservice.py", line 38, in open
service.files().list(pageSize=1, fields="files(id, name)").execute() File
"/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/googleapiclient/_helpers.py",
line 130, in positional_wrapper
return wrapped(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/googleapiclient/http.py",
line 923, in execute
resp, content = _retry_request(
^^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/googleapiclient/http.py",
line 222, in _retry_request
raise exception File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/googleapiclient/http.py",
line 191, in _retry_request
resp, content = http.request(uri, method, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google_auth_httplib2.py",
line 209, in request
self.credentials.before_request(self._request, method, uri, request_headers) File
"/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google/auth/credentials.py",
line 156, in before_request
self.refresh(request) File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google/oauth2/service_account.py",
line 438, in refresh
access_token, expiry, _ = _client.jwt_grant(
^^^^^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google/oauth2/_client.py",
line 312, in jwt_grant
response_data = _token_endpoint_request(
^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google/oauth2/_client.py",
line 272, in _token_endpoint_request
response_status_ok, response_data, retryable_error = _token_endpoint_request_no_throw(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File
"/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google/oauth2/_client.py",
line 219, in _token_endpoint_request_no_throw
request_succeeded, response_data, retryable_error = _perform_request()
^^^^^^^^^^^^^^^^^^ File
"/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google/oauth2/_client.py",
line 195, in _perform_request
response = request(
^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/google_auth_httplib2.py",
line 119, in call
response, data = self.http.request(
^^^^^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/httplib2/init.py",
line 1724, in request
(response, content) = self._request(
^^^^^^^^^^^^^^ File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/httplib2/init.py",
line 1444, in _request
(response, content) = self._conn_request(conn, request_uri, method, body, headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File
"/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/httplib2/init.py",
line 1366, in _conn_request
conn.connect() File "/home/pablo/Desktop/estacion_captura/venvs/estacion_captura2/lib/python3.11/site-packages/httplib2/init.py",
line 1156, in connect
sock.connect((self.host, self.port)) TimeoutError: timed out


排查方向及解决方案

1. 针对token刷新阶段的超时优化

从错误栈看,超时发生在服务账号获取access token的阶段(jwt_grant调用),而非Drive API请求本身。当前设置的全局socket.setdefaulttimeout未被google-auth库继承,建议给auth请求单独配置超时:

import httplib2

# 替换原credentials初始化后的代码
http = httplib2.Http(timeout=timeout_in_sec)
credentials.authorize(http)
# 构建service时传入带超时的http客户端
service = build('drive', 'v3', credentials=credentials, http=http)

2. 扩大重试策略覆盖范围

googleapiclient的默认重试只覆盖Drive API请求,token刷新的重试由google-auth库控制,可配置自定义重试逻辑:

from google.auth.transport.requests import Request as AuthRequest
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# 配置重试策略
retry_strategy = Retry(
    total=5,
    backoff_factor=1,
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["POST"]  # token请求用POST
)
adapter = HTTPAdapter(max_retries=retry_strategy)
auth_request = AuthRequest()
auth_request.mount("https://", adapter)

# 刷新token时使用带重试的请求对象
credentials.refresh(auth_request)

3. 树莓派网络层面排查

  • DNS解析检查:切换DNS服务器为8.8.8.8,或定期执行sudo systemd-resolve --flush-caches清空DNS缓存,避免解析异常。
  • WiFi稳定性优化:若用WiFi连接,执行sudo iwconfig wlan0 power off关闭无线网卡电源管理,防止休眠断连;给树莓派分配固定IP,避免DHCP续租时的网络波动。
  • 路由器排查:重启家用路由器,排除路由器长时间运行导致的临时丢包问题。

4. 服务账号配置优化

  • 更新服务密钥:登录Google Cloud控制台,检查服务账号密钥的创建时间,重新生成新密钥替换现有my_credentials.json文件。
  • 缓存access token:手动指定token缓存路径,减少重复请求token的次数:
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
import pickle

token_path = "token.pickle"
if os.path.exists(token_path):
    with open(token_path, 'rb') as token:
        credentials = pickle.load(token)
if not credentials or not credentials.valid:
    if credentials and credentials.expired and credentials.refresh_token:
        credentials.refresh(Request())
    else:
        credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
    with open(token_path, 'wb') as token:
        pickle.dump(credentials, token)

内容的提问来源于stack exchange,提问作者Pablo Rios

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:14:53