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

Google Sheets读取请求配额超限(Error 429)排查求助

问题详情

报错信息

gspread.exceptions.APIError: {'code': 429, 'message': "Quota exceeded for quota metric 'Read requests' and limit 'Read requests per minute per user' of service 'sheets.googleapis.com' for consumer 'project_number:981210703596'.", 'status': 'RESOURCE_EXHAUSTED', 'details': [{'@type': 'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'RATE_LIMIT_EXCEEDED', 'domain': 'googleapis.com', 'metadata': {'quota_limit_value': '300', 'consumer': 'projects/981210703596', 'quota_location': 'global', 'service': 'sheets.googleapis.com', 'quota_limit': 'ReadRequestsPerMinutePerUser', 'quota_metric': 'sheets.googleapis.com/read_requests'}}, {'@type': 'type.googleapis.com/google.rpc.Help', 'links': [{'description': 'Request a higher quota limit.', 'url': 'https://cloud.google.com/docs/quota#requesting_higher_quota'}]}]}

执行代码

def agregar_datos_a_sheet(self, poblacion, sustitutos, modulos, fecha_inicio, fecha_final, worksheet, ambiente):    
    # Creamos una lista con los datos a agregar
    modulos = modulos.split(",")
    datos_usuarios = []
    for i in range(len(poblacion)):
        datos_usuarios.append(
            [poblacion[i], '', sustitutos[i], '', fecha_inicio, fecha_final])
    if ambiente == 'MercadoP':
        permisos = Configuration_Manager().get_proxy_ssff()['Permisos_Mercado_P']
    else:
        permisos = Configuration_Manager().get_proxy_ssff()['Permisos_Mercado_D']
    #Inserto los IDs de usuarios y fechas
    worksheet.sheet1.insert_rows(datos_usuarios, row=2)
    time.sleep(60)
    for modulo in modulos:
        if modulo in permisos:
            columnas_permisos = permisos[modulo]
            num_usuarios = int(len(poblacion))
            update_requests = []
            #try:
            for i in range(2, num_usuarios + 2):
                for col in columnas_permisos:
                    update_requests.append({
                        'updateCells': {
                            'rows': {
                                'values': [{
                                    'userEnteredValue': {'stringValue': 'YES'}
                                }]
                            },
                            'fields': 'userEnteredValue',
                            'start': {
                                'sheetId': worksheet.sheet1.id,
                                'rowIndex': i - 1,
                                'columnIndex': col - 1
                            }
                        }
                    })
            batch_update_requests = {'requests': update_requests}
            worksheet.batch_update(batch_update_requests)
            time.sleep(60)

核心问题

  • 报错触发在worksheet.batch_update(batch_update_requests)执行前,而非预期的该行
  • 已尝试添加time.sleep()、替换append.rows()为insert_row()等方法,429配额超限错误仍持续

测试数据

Modulos:  ['cm', 'pm']
poblacion : ['30038393', '30034917', '30019948', '30041170', '30024223', '30038393', '30034917', '30019948', '30041170', '30024223', '30038393', '30034917', '30019948', '30041170', '30024223', '30038393', '30034917', '30019948', '30041170', '30024223', '30038393', '30034917', '30019948', '30041170', '30024223']
sustitutos: ['30038393', '30038393', '30038393', '30038393', '30038393', '30034917', '30034917', '30034917', '30034917', '30034917', '30019948', '30019948', '30019948', '30019948', '30019948', '30041170', '30041170', '30041170', '30041170', '30041170', '30024223', '30024223', '30024223', '30024223', '30024223']
fecha_inicio : '01-03-2023 00:00'
fecha_final : '11-03-2023 00:00'
permisos : {'rc': [11, 15, 18, 21, 29, 33, 36], 'ec': [11, 21, 22, 33, 36],
           'pm': [9, 11, 12, 13, 15, 17, 19, 23, 24, 26, 28, 32, 38, 39, 40], 'cm': [10, 14, 16, 20, 22, 33, 36]}

问题分析与解决建议

核心原因定位

报错提示读请求每分钟配额超限(300次/分钟),但错误触发在batch_update前,说明:

  1. worksheet.sheet1.insert_rows或循环中重复访问worksheet.sheet1.id可能隐式发起了大量读请求
  2. 当前代码的批量更新逻辑未做合并,导致单批次请求数量过多,连带触发配额消耗

具体优化方案

1. 减少隐式读请求

提前缓存工作表ID,避免循环中多次访问worksheet.sheet1.id(每次访问可能触发读请求):

# 在循环前缓存sheet ID
sheet_id = worksheet.sheet1.id
# 后续构建update_requests时直接使用缓存的sheet_id
'start': {
    'sheetId': sheet_id,
    'rowIndex': i - 1,
    'columnIndex': col - 1
}

2. 合并批量更新请求

当前代码为每个单元格生成独立的updateCells请求,可合并同行的多列更新,大幅减少请求数量:

update_requests = []
sheet_id = worksheet.sheet1.id
# 按行分组处理,合并同一行的多列更新
for i in range(2, num_usuarios + 2):
    row_updates = []
    # 收集该行所有需要设置为YES的单元格值
    for _ in columnas_permisos:
        row_updates.append({'userEnteredValue': {'stringValue': 'YES'}})
    # 生成单个覆盖多列的更新请求
    update_requests.append({
        'updateCells': {
            'rows': {'values': row_updates},
            'fields': 'userEnteredValue',
            'start': {
                'sheetId': sheet_id,
                'rowIndex': i - 1,
                'columnIndex': min(columnas_permisos) - 1  # 从该行最左的目标列开始
            }
        }
    })

3. 动态控制请求速率

替换固定60秒休眠,实现更灵活的速率控制:

  • 捕获429错误后,使用响应头中的Retry-After值进行精准休眠
  • 实现指数退避策略(如首次休眠1秒,之后每次翻倍,直到最大阈值)

4. 排查配额消耗点

启用gspread调试日志,明确所有API请求的类型和数量:

import logging
logging.basicConfig(level=logging.DEBUG)

通过日志可以定位到哪些操作在消耗读配额,针对性优化。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:40:15