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

使用concurrently并行执行脚本时始终返回退出码1的问题

解决Concurrently运行Mock服务与测试后退出码异常的问题

从你提供的日志和代码来看,核心问题是测试进程正常退出后,Mock服务进程收到SIGTERM信号却没有正确返回退出码0,导致整个Concurrently命令最终返回退出码1。下面一步步分析原因并给出解决方案:

问题核心分析

从日志可以明确看到:

[1] npm run test-single-run exited with code 0 --> Sending SIGTERM to other processes..
[0] node ./tools/mock-webapi/mock-webapi.js exited with code 1

测试进程成功结束后,Concurrently向Mock服务发送了SIGTERM信号,但Mock服务最终还是返回了错误退出码。你的信号处理代码存在一个关键误区,再加上可能的异步清理不彻底,导致了这个问题:

  1. SIGKILL信号无法被捕获:你监听了SIGKILL信号,但这个信号是操作系统强制杀死进程的信号,Node.js进程根本无法捕获和处理,这个监听完全无效,反而可能干扰正常的退出逻辑。
  2. 信号处理逻辑不够健壮:没有处理重复触发信号的情况,也没有设置超时兜底,可能因为server.close()卡住导致进程无法正常退出。

解决方案步骤

1. 修正信号处理代码

首先移除无效的SIGKILL监听,然后优化SIGTERM和SIGINT的处理逻辑,确保进程能优雅退出:

let isShuttingDown = false;

// 只保留可捕获的信号监听
process.on('SIGTERM', handleGracefulShutdown);
process.on('SIGINT', handleGracefulShutdown);

function handleGracefulShutdown(signal) {
  if (isShuttingDown) return; // 防止重复触发退出逻辑
  isShuttingDown = true;

  console.log(`Received ${signal}, starting graceful shutdown for mock server (PID: ${process.pid})`);

  // 关闭Web服务
  server.close((err) => {
    if (err) {
      console.error('Failed to close mock server:', err);
      process.exit(1);
    }
    console.log('Mock server closed successfully');
    process.exit(0);
  });

  // 设置超时兜底,防止server.close()卡住
  setTimeout(() => {
    console.error('Mock server shutdown timed out, forcing exit');
    process.exit(0);
  }, 5000); // 5秒超时,可根据实际情况调整
}

2. 验证Mock服务单独退出行为

先单独运行Mock服务,手动发送SIGTERM信号验证是否能正常返回退出码0:

  • 启动Mock服务:node ./tools/mock-webapi/mock-webapi.js
  • 获取进程PID:ps aux | grep mock-webapi.js(Linux/macOS)或用任务管理器(Windows)
  • 发送SIGTERM信号:kill -SIGTERM <PID>(Linux/macOS)或taskkill /PID <PID> /T(Windows)
  • 查看退出码:echo $?(Linux/macOS)或$LASTEXITCODE(PowerShell)

如果单独测试时退出码是0,说明信号处理逻辑没问题,再回到Concurrently场景测试。

3. 优化Concurrently命令与版本

  • 升级Concurrently到最新版本,旧版本可能存在参数兼容问题:
    npm install concurrently@latest --save-dev
    
  • 可以加上--prefix "[{name}]"参数让日志更清晰,方便排查:
    concurrently -k --success first --prefix "[{name}]" "node ./tools/mock-webapi/mock-webapi.js" "npm run test-single-run"
    

4. 清理额外资源(如果需要)

如果Mock服务使用了其他资源(比如数据库连接、定时器、WebSocket连接等),需要在handleGracefulShutdown函数中手动清理,确保事件循环能顺利清空:

function handleGracefulShutdown(signal) {
  // ... 原有逻辑 ...
  
  // 清理定时器
  clearInterval(yourIntervalId);
  clearTimeout(yourTimeoutId);
  
  // 关闭数据库连接(如果有)
  // dbClient.end();
}

总结

通过移除无效的SIGKILL监听、优化优雅退出逻辑、验证单独运行行为,再配合最新版的Concurrently,应该就能解决退出码异常的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:40:45