遇到限流时,第一件该做的事不是继续重试,而是先判断已经拿到的结果属于哪一种:如果每批数据都带独立标识、可以逐批落盘,那么限流只是拖慢进度,已有结果可以保留;如果脚本把整轮结果攒在内存里、最后一次性写入,那么限流导致的进程中断会让全部结果一起丢失,此时应立刻停止调用,先改写入方式再继续。这个判断决定了后续是“边等边补”还是“先改结构再重跑”。
限流本身只说明调用频率被限制,并不说明已返回的数据无效。真正决定损失大小的是脚本的写入时机。可以用一个简单依据区分:查看脚本里写入文件或数据库的位置,是在每次请求返回后立刻执行,还是在整个循环结束后统一执行。前者属于可保留型,后者属于易丢失型。
如果无法从代码判断,可以做一个假设性验证:手动触发一次小批量调用,在循环中途强制终止进程,然后检查输出文件是否存在且内容完整。若文件为空或不存在,就按易丢失型处理。
当确认每批结果都已写入磁盘,处理重点从“保住数据”转为“保住进度”。此时不要因为限流就立刻放弃整轮任务,也不要在同一时间窗口内反复重试,因为密集重试可能延长限制时间。
具体动作分三步。第一步,记录已经成功写入的最大批次或最后一条唯一键,作为续跑起点。第二步,把请求间隔调大到明显低于触发限流的频率,例如原来每秒一次改为每几秒一次,具体间隔需要根据实际返回的限流提示或响应状态调整,不能凭猜测设定。第三步,重新运行脚本时从续跑起点开始,并在每次写入前检查该键是否已存在。
这个动作的结果会直接影响下一步:如果续跑后不再触发限流,说明当前间隔可用,可以保持到任务结束;如果仍然触发,说明限制不是单纯由请求频率引起,可能还涉及并发数或单次请求量,需要进一步降低并发或拆分批次。
如果脚本属于易丢失型,继续在原结构上重试没有意义,因为下一次中断仍会清空全部结果。此时应暂停调用,先修改脚本的写入逻辑,把“最后统一保存”改为“每批返回后立即追加或覆盖写入”。
修改时注意两点。一是写入格式要支持追加,例如每行一条记录的文件,或带唯一键的数据库表,避免每次写入都覆盖整个文件。二是写入动作要放在请求成功之后、下一次请求之前,确保任何一次中断最多只丢失当前这一批。
改完之后再重新调用,此时即使再次遇到限流,已写入的部分仍然保留。这个动作的结果决定后续策略:如果修改后能稳定续跑,说明问题已经收敛到调用频率;如果写入本身报错或文件被锁,需要先解决写入冲突,否则限流问题会被写入问题掩盖。
有一种情况需要单独处理:限流返回的是明确的等待时间,而脚本本身已经支持逐批落盘。此时可以选择等待后继续,但等待期间不应保持高频探测。更稳妥的做法是把等待时间作为下一次调用的最早起点,而不是循环查询是否恢复。
另一种例外是数据本身允许重复获取且成本很低。如果重新调用一遍的代价远小于修改脚本和续跑逻辑的代价,那么直接放弃已有结果、从头以更低频率重跑也是合理选择。判断依据是比较“修改加续跑的时间”和“完整重跑的时间”,而不是默认保留一定优于重跑。
还需要注意,限流提示消失不等于限制已经解除。有些限制按时间窗口计算,窗口未结束前恢复调用可能再次触发。可以用一次单独的低频请求作为探测,而不是立即恢复原频率。这一步的结果决定是继续按原计划跑,还是把整轮任务拆成更小的批次分散到更长时间内完成。
无论当前属于哪种条件,都可以在脚本中固定一个检查点:每完成一批写入后,记录该批的唯一键和完成时间。这样下次遇到限流时,不需要重新判断哪些结果已经拿到,直接读取检查点即可。检查点本身也应写入磁盘,而不是只打印在终端里。
这个动作的结果是让限流从“可能丢失全部结果”变成“只影响剩余批次”。如果检查点记录完整,后续续跑只需从最后一个键之后开始;如果检查点缺失或时间戳混乱,说明写入和记录没有同步,需要先修复同步关系再继续调用。