You need to enable JavaScript to run this app. Node.js CLI迁移脚本提前退出未执行migrate方法如何解决
优惠活动
大模型
产品
解决方案
定价
更多

Node.js CLI迁移脚本提前退出未执行migrate方法如何解决

问题根因
  • 你代码里所有IO操作(文件读取、执行shell命令)都是异步非阻塞的,触发任务后不会等结果返回就会继续执行后续代码
  • 你在fs.readdir的回调里遍历完文件立刻调用了process.exit(),此时所有migrate触发的shell任务还没执行完,脚本就直接退出了
  • 原migrate函数内部也错误写了process.exit(),只要任意一个任务执行完就会直接退出脚本,导致后续任务无法执行
  • Array.prototype.forEach不支持等待异步任务执行完成,即使你给migrate加了async,forEach也不会等所有异步任务结束
修复方案

我们统一用async/await改写异步逻辑,保证所有迁移任务执行完成后再退出脚本:

第一步:改写migrate函数

首先用util.promisify把回调式的exec转成Promise版本,去掉内部的process.exit(),把执行结果返回给上层统一处理:

const { promisify } = require('util');
const exec = promisify(require('child_process').exec);

const migrate = async (space, env, migration) => {
  try {
    const { stdout, stderr } = await exec(`migrate ${migration} "${space}" ${env}`);
    if (stderr) {
      console.log(`stderr: ${stderr}`);
      throw new Error(stderr);
    }
    success(stdout);
    return stdout;
  } catch (error) {
    // 原有错误处理switch逻辑放这里
    throw error;
  }
};

第二步:改写migrateAll函数

统一用fs.promises的异步API,替换回调写法,等待所有迁移任务执行完成后再统一处理退出:

const migrateAll = async (app, env, source) => {
  // 读取配置文件
  const contents = await fs.promises.readFile(config, "utf8");
  this.config = JSON.parse(contents);
  const spaceId = this.config.applications[app].space_id;
  // 读取目录文件
  const files = await fs.promises.readdir(source, "utf8");
  console.log(`共找到${files.length}个待迁移文件`);

  // 生成所有迁移任务的Promise数组
  const migrateTasks = files.map((file) => {
    console.log(chalk.yellow(`Migrating "${file}" to the "${env}" environment for "${app}"`))
    return migrate(file, env, app);
  });

  // 等待所有任务执行完成(如果需要串行执行可以用for of循环挨个await)
  await Promise.all(migrateTasks);
  console.log(chalk.green('所有迁移任务执行完成'));
  process.exit(0);
};

第三步:改写上层调用逻辑,等待异步任务执行

因为migrateAll现在是异步函数,返回Promise,所以上层调用也要加await:

const parseFlags = async () => {
  process.argv.splice(2).forEach((arg) => {
    let parts = arg.split("=");
    switch (parts[0]) {
      // 原有参数解析逻辑保留
    }
  });

  if (all) {
    // 等待迁移任务执行完成
    await migrateAll(app, env, source);
  }

  return { app, env, source };
};

const run = async () => {
  try {
    intro();
    checkSettings();
    const { app, env, source } = await parseFlags();
    // 原有非迁移场景的后续逻辑保留
  } catch (err) {
    complain(err);
    process.exit(1);
  }
};

run();
额外注意

如果待迁移文件数量很多,直接用Promise.all会同时触发大量shell进程,可能导致系统资源不足,你可以改成串行执行的写法:

// 替换原来的Promise.all部分
for (const file of files) {
  console.log(chalk.yellow(`Migrating "${file}" to the "${env}" environment for "${app}"`))
  await migrate(file, env, app);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 14:15:01