Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent ctrl+c killing spawned processes in Java

Tags:

java

[NB. This is related to How do I launch a completely independent process from a Java program? but different]

I want to be able to spawn external processes (shell scripts) from a "manager" Java process that should keep running when the JVM is killed - but it seems that when I kill the parent Java program the child is killed too (note, the behaviour is different if the JVM exits naturally). The simplest test program I have is:

public class Runit {

    public static void main(String args[]) throws IOException, InterruptedException {
        Runtime.getRuntime().exec(args[0]);

        // doesn't work this way either
        // ProcessBuilder pb = new ProcessBuilder(args[0]);
        // pb.start();

        while (true) {
            System.out.println("Kill me");
            Thread.sleep(2000);
        }
    }
}

and external script:

#!/bin/sh

while [ 1 ] ; do 
    ls
    sleep 1
done

run as

java -classpath jar-with-dependencies.jar temp.exec.Runit runit.sh

If the manager simply exits (i.e. take out the "while" loop in the Java program) then the spawned process keeps running, but when I Ctrl+c the Java program the external program is killed too which is not what I want.

I'm using OpenJDK 1.6 on Ubuntu.

Edit1: Changing the exec to

Runtime.getRuntime().exec("/usr/bin/nohup " +  args[0]);

doesn't help.

Edit2: Adding a shutdown hook as described in How to gracefully handle the SIGKILL signal in Java doesn't stop the Ctrl+c being propagated to the child.

like image 758
Ian Rogers Avatar asked Jul 29 '14 09:07

Ian Rogers


1 Answers

Vladimir gave the hint we needed! (Sorry, beat Lukasz to it)

Add another script spawn_protect.sh

#!/bin/sh

LOG=$1
shift 

nohup $* > $LOG 2>&1  &

And change the manager to:

public class Runit {
    public static void main(String args[]) throws IOException, InterruptedException {
        Runtime.getRuntime().exec(args);
        while (true) {
            System.out.println("Kill me");
            Thread.sleep(5000);
        }
    }
}

Then run as:

java -classpath jar-with-dependencies.jar temp.exec.Runit spawn_protect.sh /tmp/runit.log runit.sh

Now runit.sh is really detached from the JVM process!

like image 175
Ian Rogers Avatar answered Sep 28 '22 19:09

Ian Rogers