const pLimit = require('p-limit');
const limit = pLimit(30);
await Promise.all(urls.map(u => limit(() => fetch(u))));

批量同步任务用 Promise.all 一次打出 2000 个请求,下游网关 503 率瞬间到 40%,本机报 EMFILE。改成完全串行又要跑四个小时。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,Promise.all 不限制并发,所有请求同一时刻建立连接,下游连接池和文件描述符同时见底。失败重试再叠一层流量,恢复更慢。

「异步并发过高」改完先别急着全量,挑一台机器放半天,真有问题这段时间就能看出来。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。

处理上按这个顺序:用 p-limit 或自写队列把并发压到 20 到 50;失败请求加指数退避 不要立刻重试;单批任务加整体超时 别让一个慢请求拖住全批;盯下游 503 率和本机 fd 数量再调并发。

改完只确认一件事:同样 2000 个请求下游 503 归零 总耗时比串行缩短到二十分钟以内。

作者 9823189