Skip to content

Instantly share code, notes, and snippets.

@hpoul
Created September 3, 2014 16:12
Show Gist options
  • Select an option

  • Save hpoul/83ff1a63c13cc49a4839 to your computer and use it in GitHub Desktop.

Select an option

Save hpoul/83ff1a63c13cc49a4839 to your computer and use it in GitHub Desktop.
NuProcess - Possible race condition on linux with fast exiting processes
package playground;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import com.zaxxer.nuprocess.NuAbstractProcessHandler;
import com.zaxxer.nuprocess.NuProcess;
import com.zaxxer.nuprocess.NuProcessBuilder;
/**
* Launching with:
* java -jar nuprocessproblem.jar 1000 echo test
* or
* java -jar nuprocessproblem.jar 1000 bash -c "echo test"
* produces on linux about ~ 5% failures
*
* java -jar nuprocessproblem.jar 1000 bash -c "sleep 0.01 ; echo test"
* works 100%
*/
public class NuProcessProblem {
public static void main(String[] args) {
int count = 100;
List<String> command = new ArrayList<>();
if (args.length > 0) {
count = Integer.parseInt(args[0]);
for (int i = 1 ; i < args.length ; i++) {
command.add(args[i]);
}
}
int success = 0, fail = 0;
List<String> errors = new ArrayList<>();
for (int i = 0 ; i < count ; i++) {
try {
startEchoProcess(command).toCompletableFuture().get();
success++;
} catch (InterruptedException | ExecutionException e) {
errors.add(e.getLocalizedMessage());
e.printStackTrace();
fail++;
}
}
System.out.println("All Errors: " + errors);
System.out.println("Result: success: " + success + " / fail: " + fail);
}
public static CompletionStage<Void> startEchoProcess(List<String> command) {
if (command.isEmpty()) {
command = Arrays.asList("echo", "-i", "blubb", "-acodec", "libmp3lame", "-y", "asdf");
}
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
NuProcessBuilder builder = new NuProcessBuilder(command);
builder.setProcessListener(new NuAbstractProcessHandler() {
@Override
public void onStdout(ByteBuffer buffer) {
logOutput("STDOUT: ", buffer);
}
@Override
public boolean onStdinReady(ByteBuffer buffer) {
return false;
}
@Override
public void onStderr(ByteBuffer buffer) {
logOutput("STDERR: ", buffer);
}
@Override
public void onStart(NuProcess nuProcess) {
System.out.println("onStart");
}
@Override
public void onExit(int exitCode) {
System.out.println("onExit: " + exitCode);
if (exitCode == 0) {
completableFuture.complete(null);
} else {
completableFuture.completeExceptionally(new RuntimeException("exited with code: " + exitCode));
}
}
private void logOutput(String prefix, ByteBuffer buffer) {
if (buffer == null) {
return;
}
byte[] buf = new byte[buffer.remaining()];
buffer.get(buf);
System.out.println(prefix + " " + new String(buf).trim());
}
});
NuProcess process = builder.start();
return completableFuture;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment