0

I have to launch console commands from java to publish to verdaccio. So it works(pretty bad), but for few packages processes stucks. When I destroy them it returns code 137, witch means not enough memory. I watched in profiler, I have much more free heap, then used.

Maybe it's not because not enough memory.

How to understand why it stucks and how to fix it?

    protected String execCommand(List<String> command) throws IOException, NpmAlreadyExistException{

        ProcessBuilder pb = new ProcessBuilder(command);
        File workingFolder = new File(System.getProperty("user.dir"));
        pb.directory(workingFolder);
        Process process = pb.start();
        try {
            boolean finished = process.waitFor(60, TimeUnit.SECONDS);
            logger.info("PROC FINISHED: " + finished);
            if (!finished) {
                process.destroyForcibly();
                int exitCode = process.waitFor();
                logger.info("PROC EXIT CODE: " + exitCode);
                return null;
            }
        } catch (InterruptedException e) {
            logger.info("PROCESS WAS INTERRUPTED!!!");
            logger.info(e.getMessage());
            return null;
        }

        logger.info("PROC EXIT CODE: " + process.exitValue());

        String s;
        BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        StringBuilder err = new StringBuilder();
        while ((s = stdErr.readLine()) != null) {
            err.append("\n").append(s);
        }
        stdErr.close();

        BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
        StringBuilder result = new StringBuilder();
        while ((s = stdInput.readLine()) != null) {
            result.append("\n").append(s);
        }
        stdInput.close();
        process.destroy();

        logger.info(String.format("execCommand response [stdin]: %s", result));
        logger.info(String.format("execCommand response [stdErr]: %s", err));


        if (err.length() != 0) {
            if (err.toString().contains("Update the 'version' field in package.json and try again.")) {
                throw new NpmAlreadyExistException("Пакет с таким именем и версией уже существует в репозитории.");
            }
        }
        return result.toString();
    }

profiler

Thank you!

mamol
  • 91
  • 2
  • 11
  • 4
    You're not reading the process' standard output and standard error while you wait for it. This can easily lead to a deadlock (where the process is blocked due to a filled-up output buffer). See [this question](https://stackoverflow.com/questions/5483830/process-waitfor-never-returns). – Generous Badger Sep 07 '22 at 09:02
  • 2
    just my two cents to @GenerousBadger suggestion: https://stackoverflow.com/questions/8595748/java-runtime-exec – Andrey B. Panfilov Sep 07 '22 at 09:04
  • @GenerousBadger You mean I should use getInputStream next line after process.waitFor? – mamol Sep 07 '22 at 09:12
  • 2
    No ... before it. – Stephen C Sep 07 '22 at 09:13
  • @StephenC I used it before and this method stuck at stdInput.getLine() because there wasn't any input. – mamol Sep 07 '22 at 09:15
  • @GenerousBadger, StephenC Thank you it was deadlock, I moved streams upper and all works. – mamol Sep 07 '22 at 09:20

0 Answers0