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

为什么使用setInterval的Node.js脚本运行一段时间后会停止执行?

问题核心原因

你遇到的问题和PM2部署关系不大,主要是setInterval的使用逻辑有问题,加上异步任务没有做错误处理和资源管控,累计到阈值后触发了阻塞/资源耗尽:

  • 第一,setInterval不会等待异步任务执行完成就会推入下一次任务。你写的3个函数都是调用API、写数据库的IO密集异步任务,如果某次三个函数总执行时间超过2分钟,setInterval会直接把下一轮的三个函数塞进事件队列,多轮堆叠后Node进程的内存、socket连接、数据库连接都会被打满,后续的任务自然无法执行。
  • 第二,你没有给异步函数加错误捕获和资源释放逻辑。虽然你不在意单次失败,但如果函数抛出未捕获的异常,或者API请求超时没有主动中断、数据库游标没有关闭,这些问题会累计,最终导致进程的可用资源耗尽,新的任务无法分配资源执行。
  • 第三,EC2的默认资源限制比本地开发环境严格。比如默认的TCP连接数、文件句柄数、MongoDB连接池大小都更低,本地环境资源充足能扛住的泄漏问题,在EC2上会更快暴露。

修复方案

第一步:把setInterval换成递归的setTimeout,保证上一轮任务完全执行完再调度下一轮

示例代码:

// 封装调度函数,每次执行完所有任务后再调度下一次
const scheduleJob = async () => {
  try {
    // 如果你需要三个函数并行执行,用Promise.all,如果需要串行就依次await
    await Promise.all([function1(), function2(), function3()])
  } catch (err) {
    // 统一捕获错误,避免未捕获异常影响进程
    console.error('任务执行出错:', err)
  } finally {
    // 无论成功失败,2分钟后调度下一次
    setTimeout(scheduleJob, 1000 * 120)
  }
}

app.listen(port, () => {
  // 启动第一次调度
  scheduleJob()
})

第二步:给单个函数加上超时控制和资源释放逻辑

  • 给每个API请求加上超时时间,超时后主动中断请求,避免socket一直挂着占资源
  • 给MongoDB的写操作加超时,用完的连接及时释放回连接池,不要保持无用的长连接
  • 单个函数内部加上try/catch,避免单个函数的错误影响其他函数执行

第三步:PM2配置优化

  • 给PM2的启动配置加上--time参数,记录日志的时间戳,方便排查哪次任务出了问题
  • 适当调高EC2实例的文件句柄数、TCP连接数限制,同时把MongoDB的连接池大小调整到合理范围,不要超过实例的承载上限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 11:18:03