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

Node.js 异步无限循环无报错随机中断运行该如何排查?

问题排查方案

你的循环中断大概率是某一步异步操作陷入了永久pending状态,既不resolve也不reject,导致代码永远走不到finally块,看起来像停止运行,但进程不会崩溃也没有错误日志。可按以下步骤排查:


1. 给所有异步操作加超时兜底,避免永久pending

先实现通用超时工具函数,给所有await的异步操作套上超时逻辑,超时主动抛出错误,就能进入catch块打印日志定位问题:

// 通用超时工具函数
const withTimeout = (promise, timeoutMs, desc = '') => {
  return Promise.race([
    promise,
    new Promise((_, reject) => {
      setTimeout(() => {
        reject(new Error(`操作超时[${desc}],超时时间${timeoutMs}ms`))
      }, timeoutMs)
    })
  ])
}

// 改进后的循环函数
async function infiniteLoop() {
  console.log(`[${Date.now()}] 开始新一轮循环`)
  try {
    console.log(`[${Date.now()}] 开始请求API`)
    // 给axios请求额外加超时兜底,避免配置的超时不生效
    const response = await withTimeout(axios.get(...), 10000, 'API拉取')
    console.log(`[${Date.now()}] API请求成功,共${response.data.entities.length}条数据`)

    console.log(`[${Date.now()}] 开始批量处理数据`)
    // 给整体数据处理加超时
    await withTimeout(
      Promise.all(response.data.entities.map(async (entity) => {
        console.log(`[${Date.now()}] 开始处理entity: ${entity.id}`)
        const product = new Product(entity)
        // 给单个实体处理加超时
        await withTimeout(product.resolve(), 30000, `实体处理${entity.id}`)
        console.log(`[${Date.now()}] 完成处理entity: ${entity.id}`)
      })),
      120000,
      '全量数据处理'
    )
    console.log(`[${Date.now()}] 批量处理数据完成`)
  } catch (e) {
    console.error(`[${Date.now()}] 循环执行出错:`, e)
  } finally {
    console.log(`[${Date.now()}] 进入finally,1s后重启循环`)
    setTimeout(() => infiniteLoop(), 1000)
  }
}

// 全局错误捕获,兜底所有未被catch的错误
process.on('unhandledRejection', (reason, promise) => {
  console.error(`[${Date.now()}] 未处理的Promise拒绝:`, reason, promise)
})
process.on('uncaughtException', (err) => {
  console.error(`[${Date.now()}] 未捕获的同步异常:`, err)
})

2. 排查内部实现的错误吞吃问题

  • 检查Product.resolve()方法的内部实现,有没有内部用try/catch吞掉所有错误、且没有往外抛出也没有打印日志的情况,如果内部异步操作出错被吞,同时后续逻辑停止执行,也会导致Promise永远pending。
  • 检查Prisma的配置和使用逻辑:是否配置了查询超时?有没有长事务未提交/回滚的情况?连接池大小是否足够?如果连接池占满没有释放,后续的Prisma查询会一直等待空闲连接,导致逻辑卡住。

3. 监控进程资源状态

  • 定期打印进程内存占用:console.log('内存使用:', process.memoryUsage()),排查是否存在内存泄漏、GC频繁导致进程假死的情况。
  • 打印Prisma连接池状态,排查是否连接耗尽导致查询卡住。

4. 挂死时抓取调试信息

如果上述加日志的方式还不能定位,可以用Node.js调试模式运行程序:启动时加--inspect参数,进程卡住时用Chrome开发者工具Attach到进程,查看当前挂起的异步调用栈,直接定位到卡住的代码位置。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 01:15:04