NetSuite定时脚本调用API超时 求批量等待120秒优化方案
问题分析
当前触发的SSS_REQUEST_TIME_EXCEEDED错误,本质是短时间内发送过多API请求触发了对方的速率限制(API文档明确限制为每秒3-10次),且原代码未对请求频率做任何控制,当处理记录超过10条时就会超出限制阈值。结合API文档要求,我们需要实现主动控制请求间隔和429错误重试等待的逻辑。
解决方案
以下是修改后的代码,核心优化点包括:分批处理搜索结果、每批处理后添加延迟、捕获429错误并等待120秒重试、模块化拆分逻辑提高可维护性。
define(['N/search', 'N/record', 'N/https', 'N/runtime'], function(search, record, https, runtime) { // 可配置参数,根据API限制调整 const BATCH_SIZE = 5; // 每批处理的记录数,保守匹配API速率限制 const POST_BATCH_WAIT = 1000; // 每批处理完成后的等待时间(毫秒) const RATE_LIMIT_WAIT = 120000; // 遇到429错误时的等待时间(120秒) const MAX_RETRIES = 3; // 遇到速率限制后的最大重试次数 function execute(context) { const savedSearchId = 2808; const savedSearch = search.load({ id: savedSearchId }); const searchResultSet = savedSearch.run(); let start = 0; let results; // 循环分批获取并处理搜索结果 do { results = searchResultSet.getRange({ start: start, end: start + BATCH_SIZE }); if (results.length === 0) break; // 处理当前批次的每条记录 results.forEach(result => { const salesOrderId = result.getValue({ name: 'internalid' }); const fieldValue = result.getValue({ name: 'custbody37' }); // 调用API并处理重试逻辑 const apiResponse = callApiWithRetry(fieldValue); if (!apiResponse) return; // 更新销售订单 updateSalesOrder(salesOrderId, apiResponse.data.last_event); }); // 批次处理完成后等待,避免请求过快 log.debug('Batch processed', `Waiting ${POST_BATCH_WAIT/1000}s before next batch`); sleep(POST_BATCH_WAIT); start += BATCH_SIZE; } while (results.length === BATCH_SIZE); } // 带重试逻辑的API调用函数 function callApiWithRetry(fieldValue) { const url = 'https://api.XXXXXX.com/v4/XXXX'; const headers = { 'Tracking-Api-Key': 'XXXXXXX', 'Content-Type': 'application/json' }; const body = JSON.stringify({ "awb_number": fieldValue }); for (let retry = 0; retry < MAX_RETRIES; retry++) { try { const response = https.post({ url: url, headers: headers, body: body }); // 处理429速率限制错误 if (response.code === 429) { log.warn('Rate limit triggered', `Retrying after ${RATE_LIMIT_WAIT/1000}s (attempt ${retry+1}/${MAX_RETRIES})`); sleep(RATE_LIMIT_WAIT); continue; } // 处理其他非成功状态码 if (response.code < 200 || response.code >= 300) { log.error('API request failed', `Status: ${response.code}, Body: ${response.body}`); return null; } // 解析并返回响应 return JSON.parse(response.body); } catch (e) { // 捕获请求超时错误,按速率限制逻辑重试 if (e.name === 'SSS_REQUEST_TIME_EXCEEDED') { log.warn('Request timed out', `Retrying after ${RATE_LIMIT_WAIT/1000}s (attempt ${retry+1}/${MAX_RETRIES})`); sleep(RATE_LIMIT_WAIT); continue; } log.error('API request error', e); return null; } } log.error('Max retries reached', 'Failed to get valid API response'); return null; } // 销售订单更新函数 function updateSalesOrder(salesOrderId, lastEventValue) { try { const salesOrder = record.load({ type: record.Type.SALES_ORDER, id: salesOrderId }); salesOrder.setValue({ fieldId: 'custbody417', value: lastEventValue }); salesOrder.save(); log.debug('Sales Order updated', `ID: ${salesOrderId}`); } catch (e) { log.error('Failed to update Sales Order', `ID: ${salesOrderId}, Error: ${e}`); } } // NetSuite兼容的睡眠函数 function sleep(milliseconds) { runtime.wait({ duration: milliseconds }); } return { execute: execute }; });
关键修改说明
- 分批处理:使用
getRange()分批拉取搜索结果,避免一次性处理过多记录导致请求集中爆发 - 请求频率控制:每批处理完成后添加固定延迟,主动降低请求速率,减少触发限制的概率
- 错误重试机制:捕获429错误和请求超时错误,严格按照API要求等待120秒后重试,最多重试3次
- 逻辑模块化:将API调用、订单更新拆分为独立函数,便于后续维护和调整
- 参数可配置:将批次大小、等待时间等参数设为常量,可根据实际API限制灵活调整
注意事项
- 根据API实际速率限制调整
BATCH_SIZE和POST_BATCH_WAIT:例如API允许每秒10次请求,可将BATCH_SIZE设为10,POST_BATCH_WAIT设为1000毫秒 - 定时脚本存在执行时间限制(通常为30分钟),若需处理超大量记录,建议结合脚本调度或任务链分多次执行
- 确保已在依赖中添加
N/runtime模块,否则sleep函数无法正常工作
内容的提问来源于stack exchange,提问作者penone
相关产品推荐
相关产品推荐

