Java Native Process Timeout

Java native process timeout

This is how the Plexus CommandlineUtils does it:

Process p;

p = cl.execute();

...

if ( timeoutInSeconds <= 0 )
{
returnValue = p.waitFor();
}
else
{
long now = System.currentTimeMillis();
long timeoutInMillis = 1000L * timeoutInSeconds;
long finish = now + timeoutInMillis;
while ( isAlive( p ) && ( System.currentTimeMillis() < finish ) )
{
Thread.sleep( 10 );
}
if ( isAlive( p ) )
{
throw new InterruptedException( "Process timeout out after " + timeoutInSeconds + " seconds" );
}
returnValue = p.exitValue();
}

public static boolean isAlive( Process p ) {
try
{
p.exitValue();
return false;
} catch (IllegalThreadStateException e) {
return true;
}
}

Process Builder and Process in Java - how to execute a process with a timeout :?

It is a bug in Java's Process.destroy() implementation on Windows. The problem is that the batch-script (or its executing shell) is killed, but does not kill its own child processes (the ping here). Thus, ping is still running after the .destroy(), and also after the .waitFor(). But somehow the VM still waits for the ping to finish before finishing itself.

It seems there is nothing you can do here from the Java side to really kill the ping reliably.

You may think about using start (in your batch script or outside) to invoke your ping as a separate process.

(See also this previous discussion.)

Or change to a unix-like operation system.

How to add a timeout value when using Java's Runtime.exec()?

public static int executeCommandLine(final String commandLine,
final boolean printOutput,
final boolean printError,
final long timeout)
throws IOException, InterruptedException, TimeoutException {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(commandLine);
/* Set up process I/O. */
...
Worker worker = new Worker(process);
worker.start();
try {
worker.join(timeout);
if (worker.exit != null)
return worker.exit;
else
throw new TimeoutException();
} catch(InterruptedException ex) {
worker.interrupt();
Thread.currentThread().interrupt();
throw ex;
} finally {
process.destroyForcibly();
}
}

private static class Worker extends Thread {
private final Process process;
private Integer exit;
private Worker(Process process) {
this.process = process;
}
public void run() {
try {
exit = process.waitFor();
} catch (InterruptedException ignore) {
return;
}
}
}

Connection timeout in java?

There is no built-in timeout for this. What I do is to use a different thread and interrupt the thread after the timeout.

It's easier to use FutureTask for this. See my answer to this question,

java native Process timeout

httpclient timeouts? can's seem to get them to stick

All the timeout values you set only try to limit the time for a specific operation, not total time of the request. In certain circumstances, the timeout doesn't work at all. For example, the connection timeout has no effect if the IP is blocked by firewall.

The only solution I found is to start my request in a different thread and time it out myself. You can use ThreadPool and FutureTask for this. See my answer to this question,

java native Process timeout

How to make the HTTP connection timeout/disconnected after a time interval?

There are 2 timeouts involved in HTTPClient, try to set both,

  client.getHttpConnectionManager().
getParams().setConnectionTimeout(5000);
client.getHttpConnectionManager().
getParams().setSoTimeout(5000);

However, the values will be ignored if the connection is stuck in a native socket call. So you might have to run the request in a different thread so you can time it out. See my answer to this question on how to do that,

java native Process timeout

Java: set timeout on a certain block of code?

Yes, but its generally a very bad idea to force another thread to interrupt on a random line of code. You would only do this if you intend to shutdown the process.

What you can do is to use Thread.interrupt() for a task after a certain amount of time. However, unless the code checks for this it won't work. An ExecutorService can make this easier with Future.cancel(true)

Its much better for the code to time itself and stop when it needs to.

Killing self fork JVM. PING timeout elapsed

All of this is discussed in mailing list, but I'll summarize below.

Background

By default (and in our case), Maven, running in one JVM, forks a child process running another JVM to run tests. The parent gives the child commands via the child's stdin. Specifically, the parent sends a NOOP command to the child to let it know it's still alive.

Answer

ForkedBooter.java sets up two threads indirectly. commandReader reads commands from the parent process via stdin. listenToShutdownCommands adds a listener to commandReader to set an AtomicBoolean pingDone to true when the NOOP command is received. listenToShutdownCommands also schedules a job to run every 30s that does something like this (modified for easy reading):

boolean hasPing = pingDone.getAndSet( false );
if ( !hasPing ) {
exit( 1 );
log( "Killing self fork JVM. PING timeout elapsed." );

So the error message is claiming that the child did not read a NOOP from the parent.

Cause of the error

You may be able to predict what the problem is from the above description alone. I added logging to see what was going on in my case, and found that sometimes there would a pause minutes long during which commandReader would not read any NOOPs (and usually pingJob would not run either). When there was time for the two to run, pingJob may run twice in a row thereafter before commandReader gets its turn.

Simply, there is nothing in this code that ensures the OS will run the thread that reads from stdin often enough. It's possible for there to be a 3m pause in one thread because we've asked the OS to run a dozen other threads with equal priority, all with things to do--they're not sleeping, yielding, or blocking for IO. We have a heavyweight test that did indeed have a couple of 3m pauses, even on a 4-core processor.



Related Topics



Leave a reply



Submit