Java - Running a subprocess works locally but fails with "broken pipe" when ran on Heroku?

491 views Asked by At

Just as a background, I have a Java-based Discord bot deployed on Heroku using the 1 free worker dyno. I need to run a .exe file (stockfish 12 executable), pass input into it and process output from it. I'm using Java RunTime to create this Process but when I try to send input to it with the flush() method the broken pipe error is thrown. I assume Heroku must be closing the input / output stream somehow because this code runs fine locally. Does Heroku have a limit on creating sub processes?

app[worker.1]: chess.player.ai.stockfish.exception.StockfishEngineException: java.io.IOException: Broken pipe app[worker.1]: at chess.player.ai.stockfish.engine.UCIEngine.sendCommand(UCIEngine.java:39) app[worker.1]: at chess.player.ai.stockfish.engine.UCIEngine.passOption(UCIEngine.java:77) app[worker.1]: at chess.player.ai.stockfish.engine.UCIEngine.(UCIEngine.java:23) app[worker.1]: at chess.player.ai.stockfish.engine.Stockfish.(Stockfish.java:13) app[worker.1]: at chess.player.ai.stockfish.StockFishClient.(StockFishClient.java:21) app[worker.1]: at chess.player.ai.stockfish.StockFishClient$Builder.build(StockFishClient.java:80)

EDIT: I tried to simplify the program by hard coding a single command and it still fails to get past the writer.flush() line. Nothing is printed.

Process process = new ProcessBuilder().command("bin/stockfish_20090216_x64_bmi2.exe").start();

StringBuilder output = new StringBuilder();
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
writer.write("position fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" + "\n");
writer.write("go movetime 1000");
writer.flush();

String line;
while ((line = input.readLine()) != null) {
    output.append(line + "\n");
}

int exitVal = process.waitFor();
if (exitVal == 0) {
    System.out.println("success");
    System.out.println(output.toString());
}
else {
    System.out.println("error");
}
2

There are 2 answers

0
jbrouillard On BEST ANSWER

Turns out I was using the wrong binary file. Stockfish binary comes in many different formats and apparently the one that works for my local didn't work on Heroku.

2
Angelina Nikonova On

output stream closes itself. When you run a command, create a new process or this command must block a stream and await an input.

Recommend ProcessBuilder, it is more easily to configure:

new ProcessBuilder().command("cmd.exe", "/c", "command")
                    .directory(new File(path))
                    .redirectInput(new File(path, "input.txt"))
                    .redirectOutput(new File(path, "output.txt"))
                    .redirectError(new File(path, "runtime_error.txt"))
                    .start()
                    .waitFor();