遇到限流时,最该先做的不是继续重试,而是停止覆盖已有结果,把本次任务改成可续跑、可对账的状态。具体做法是:保留上一轮完整输出,把新结果写入独立批次,记录每个任务的请求状态和游标,等限流窗口过去后再只补未完成部分。这样即使脚本被中断,旧数据仍可交付,新数据也不会混入半成品。
同一段脚本在同一时间报错,团队里常出现两种理解:一种认为是调用方被限流,另一种认为是目标接口本身出错或参数不合法。两者处理方式完全不同。限流的典型特征是错误集中出现在短时间窗口内,间隔一段时间后同类请求可以恢复;任务本身失败则往往与参数、权限或数据格式相关,重试多次仍会在同一位置报错。
区分证据可以按下面顺序收集:
这一步的意义在于决定下一步动作:如果是限流,应该降速并保留断点;如果是任务失败,继续重试只会浪费配额,应该先修正参数或权限。
很多脚本默认每次运行都清空输出目录再写入,这在正常运行时没问题,一旦中途被限流,旧结果就被清掉了。更稳妥的做法是让每次运行生成独立批次目录,例如 run-2024-06-01-01,并把每个任务的完成状态单独记录。这样上一轮完整结果仍然存在,新一轮只补充未完成项。
一个假设例子:假设某次任务需要处理 500 个查询,脚本在第 180 个查询时开始持续收到限流响应。如果输出目录是覆盖式的,前 179 个结果虽然已写入,但下一次运行会清空它们;如果采用批次目录加状态文件,前 179 个结果保留,状态文件记录到第 180 个,恢复后从第 181 个继续即可。这个例子只用于说明比较方法,不代表任何真实项目的处理量。
实际动作上,建议在脚本里加一个“只写新文件、不删旧文件”的开关,并把完成游标写入独立状态文件。这个动作的结果是:限流结束后,你可以先核对旧批次是否完整,再决定是否合并新批次,而不是被迫接受一份被截断的混合结果。
确认是限流后,下一步不是立刻恢复全速,而是把请求间隔调大,并给任务加一个简单队列。队列的作用是让每个任务有明确的等待顺序,避免多个脚本同时抢配额。可以用固定间隔,也可以用递增间隔,关键是让恢复过程可观察。
判断降速是否有效的证据是:在相同时间窗口内,失败请求的比例是否下降,而不是只看总请求数是否增加。如果总请求数增加但失败比例也增加,说明降速幅度不够,应该继续调大间隔。这一步的结果会直接影响下一步:如果降速后失败比例明显下降,可以逐步恢复并发;如果失败比例不变,则要回到上一步重新判断是否真的是限流。
当运营、开发和数据同学对“是否被限流”有不同理解时,争论通常停留在感受层面。更有效的做法是把分歧转成可以核对的项目:谁在什么时间、用什么参数、调用了哪个任务、返回了什么状态、旧结果是否完整。这些项目不需要复杂系统,一个共享的状态文件或一张任务记录表就能承载。
核对时重点看三件事:
如果这三项都能核对,团队就不需要靠猜测来分配责任,而是根据记录决定是继续补跑、调整参数,还是暂停任务等待窗口恢复。需要说明的是,具体工具的限流规则、恢复时间和配额信息需要以该工具当前文档或实际返回为准,不同工具之间差异较大。
限流窗口过去后,不要直接把新批次结果覆盖到旧批次上。先对账:旧批次完成了多少、新批次补了多少、两者是否有重叠、重叠部分的结果是否一致。如果一致,可以合并;如果不一致,说明中间可能有参数变化或数据更新,需要先确认口径再决定保留哪一份。
对账这一步的结果决定了后续是继续用旧口径补跑,还是重新定义任务范围。它比单纯追求“跑完”更重要,因为限流场景下最容易出的问题不是少跑了几条,而是把不完整的新结果当成完整结果使用。把恢复后的第一次运行当作核对机会,而不是当作收尾动作,已有结果才真正被保护住。