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

Java调用Verdaccio发布包时进程卡住的原因排查与解决

Java执行Verdaccio包发布命令进程卡住问题排查与解决

问题现象

通过Java执行控制台命令向Verdaccio发布包时,部分进程出现卡住现象;强制销毁进程后返回退出码137(通常关联内存不足),但Profiler显示Java堆内存剩余远大于已使用量,排除堆内存不足的可能性。

核心原因分析

退出码137本质是进程被操作系统的OOM Killer终止,但Java堆内存充足时,问题大概率出在以下方向:

  • 子进程(npm/pnpm等发布工具)自身内存溢出,触发OS内存回收机制
  • Java未正确处理子进程的标准输出/错误输出,缓冲区满导致子进程阻塞
  • Verdaccio服务端处理发布请求时卡住(如磁盘IO慢、并发限制),导致客户端进程长期等待
  • Java执行命令的环境变量、工作目录与手动执行不一致,引发异常

针对性解决办法

1. 修复子进程IO阻塞问题

Java执行外部命令时,若未及时读取子进程的stdout/stderr,缓冲区满后子进程会被阻塞,最终可能被OS判定为无响应而终止。需修改代码异步读取输出:

public static void publishPackage(String packageDir) throws IOException, InterruptedException {
    // 构建发布命令,替换为你的Verdaccio地址
    ProcessBuilder pb = new ProcessBuilder("npm", "publish", "--registry", "http://your-verdaccio-address");
    pb.directory(new File(packageDir));
    
    Process process = pb.start();

    // 异步读取标准输出
    new Thread(() -> {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 可根据需求将输出写入日志
                System.out.println("Publish stdout: " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();

    // 异步读取错误输出
    new Thread(() -> {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.err.println("Publish stderr: " + line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }).start();

    int exitCode = process.waitFor();
    if (exitCode != 0) {
        throw new RuntimeException("Package publish failed, exit code: " + exitCode);
    }
}

2. 调整子进程内存限制

若子进程(如npm)因内存不足被Kill,可通过参数提升其内存上限:

// 在命令中添加--max-old-space-size参数,设置为4GB(根据实际情况调整)
ProcessBuilder pb = new ProcessBuilder("npm", "publish", "--registry", "http://your-verdaccio-address", "--max-old-space-size=4096");

同时检查操作系统的ulimit设置,确保子进程能获取足够内存(执行ulimit -v查看虚拟内存限制,必要时联系运维调整)。

3. 排查Verdaccio服务端状态

  • 查看Verdaccio日志(默认路径~/.config/verdaccio/logs/verdaccio.log),检查是否有发布请求超时、磁盘写入错误等记录
  • 确认Verdaccio所在服务器的磁盘空间充足、IO负载正常
  • 调整Verdaccio配置文件config.yaml,优化max_body_size(允许上传的包大小)、并发连接数等参数

4. 统一命令执行环境

确保Java进程的环境变量、工作目录与手动执行时一致:

ProcessBuilder pb = new ProcessBuilder("npm", "publish", "--registry", "http://your-verdaccio-address");
pb.directory(new File(packageDir));

// 继承或手动设置必要环境变量,如NODE_PATH、HOME
Map<String, String> env = pb.environment();
env.putAll(System.getenv());

验证步骤

  1. 手动在控制台执行发布命令,确认命令本身及Verdaccio服务正常
  2. 修改Java代码处理IO流后,测试批量发布,观察进程是否还会卡住
  3. 若仍出现137错误,用top或htop监控子进程的内存占用,确认是否为子进程内存溢出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 01:01:12