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

Nodemon运行Google Drive转存S3脚本中途无报错崩溃如何解决

问题根因分析
  • 首先[nodemon] app crashed是开发工具nodemon的提示,掩盖了进程崩溃的真实原因,没有错误日志是因为你没有对Node.js全局异常和未处理Promise拒绝做捕获逻辑
  • 内存溢出是最可能的崩溃原因:你当前的代码会一次性把所有待下载文件的内容以Buffer形式存到内存中等待批量上传,文件量过大或单个文件过大会直接占满8GB内存导致进程被系统杀掉
  • 并发逻辑错误:promises.push(await downloadFile(...))的写法会等待单个文件下载上传完成才处理下一个,同时所有文件的Buffer会堆积在内存中,完全没有利用并发能力还会加重内存负担
  • 没有控制并发数:单页1000个文件的任务如果同时发起,会触发Google Drive API或S3的限流,报错未被捕获也会直接导致进程崩溃
解决方案

1. 先捕获真实错误日志

在脚本最开头添加全局异常监听代码,方便定位具体错误:

// 全局异常捕获
process.on('uncaughtException', (err) => {
  console.error('未捕获的异常:', err, err.stack)
  process.exit(1)
})
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的Promise拒绝:', reason, promise)
  process.exit(1)
})

2. 修复并发逻辑,控制并发数

使用p-limit库控制同时执行的下载上传任务数,避免内存溢出和API限流:

  • 先安装依赖:npm i p-limit
  • 修改文件处理循环部分代码:
const pLimit = require('p-limit')
// 调整为合适的并发数,建议5-10
const limit = pLimit(5)
let promises = []
if (files.length) {
  const filesWithExt = files.filter(file => !!file.fileExtension);
  total = filesWithExt.length;
  console.log("文件总数", files.length);
  console.log("待迁移文件总数", filesWithExt.length);
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    if (file.fileExtension) {
      const path = file.name;
      // 用limit包装异步任务控制并发
      promises.push(limit(async () => {
        const exist = await s3_exist(`migration-temp-${stage}`, path);
        if (exist) {
          console.log(path, " 已存在于S3,跳过");
          return { status: 'skipped', path }
        }
        return downloadFile(stage, file.id, path, auth)
      }))
      count = count + 1;
      console.log("..... 剩余 ", total - count, " 个");
    }
  }
  await Promise.all(promises)
  // 存在下一页自动处理,无需手动输入pageToken
  if (res.data.nextPageToken) {
    console.log("开始处理下一页,令牌:", res.data.nextPageToken, "\n");
    // 这里可以调用递归函数处理下一页,或者把pageToken存到变量循环处理
  }
  process.exit(0)
}

3. 不需要nohup也可以后台运行的方法

解决脚本需要输入参数但需要后台运行的问题:

  1. 正常用node启动脚本,不要用nodemon:node index.js
  2. 完成所有用户输入(环境选择、分页参数、谷歌授权等)后,按Ctrl+Z暂停进程
  3. 输入bg命令把暂停的进程切换到后台运行
  4. 输入disown命令让进程脱离当前终端会话,关闭SSH连接后进程也会继续运行

4. 内存优化(可选,适合大文件场景)

修改下载上传逻辑为流式处理,文件内容不经过内存和本地磁盘,直接从Google Drive流传输到S3:

  • 先在helper.js中实现S3流式上传方法,使用AWS SDK的upload接口支持传入可读流作为Body
  • 修改downloadFile函数:
const downloadFile = async (stage, fileId, finalName, auth) => {
  const drive = google.drive({ version: "v3", auth });
  console.log(`正在处理 ${finalName}`);
  // 获取Google Drive下载流
  const downloadStream = await drive.files.get(
    { fileId, alt: "media" },
    { responseType: "stream" }
  );
  // 直接将流上传到S3,不占用内存
  return upload_to_s3_stream(downloadStream.data, finalName, `migration-temp-${stage}`)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 05:24:08