1

Using ProcessBuilder, I've been trying to create an independent process that doesn't get terminated when the JVM gets terminated, but nothing seems to work.

I've tried /usr/bin/nohup commands, but that still seems to terminate when the JVM that launched it is terminated. Is there any way to accomplish this in Java?

darkfrog
  • 1,053
  • 8
  • 29
  • Possible duplicate of [Process java still being killed](https://unix.stackexchange.com/q/125072), even though it is about nohup *of* Java program, not nohup *from* Java program. – Andreas Sep 18 '18 at 20:58
  • Andreas, that is very different. I'm not trying to launch `java` and disown it, I'm trying to launch a process from a running JVM instance and avoid it getting terminated as a child process when the parent (JVM instance) terminates. – darkfrog Sep 18 '18 at 21:00
  • Why does it terminate when the JVM terminates? Do you have pipes going from/to it? – that other guy Sep 18 '18 at 21:12
  • that other guy, exactly my question! :) I don't know why, but `nohup` doesn't seem to change it from happening, which seems a complete violation of the purpose of `nohup`. I have it redirecting to System out and err, but that's it. – darkfrog Sep 18 '18 at 21:13
  • `nohup` is meant to protect processes from a disappearing terminal by redirecting FDs pointing to it and ignoring SIGHUP. It does not aim to insulate a process from the death of its parent. Where are you currently redirecting the process's streams? Can you include some code to reproduce? – that other guy Sep 18 '18 at 21:15

1 Answers1

4

Well, first things first lets write a test script that validates what you're seeing:

$ cat /tmp/test.sh 
#!/bin/bash

for sig in SIGINT SIGTERM SIGHUP; do
  trap "echo Caught $sig" $sig
done

echo Traps registered, sleeping
sleep 10
echo Done sleeping, exiting

When I invoke this via:

new ProcessBuilder("/tmp/test.sh").inheritIO().start().waitFor(1, TimeUnit.SECONDS);

I see the Java process terminate after 1 second (since waitFor() timed out), but the subprocess keeps going (the Done sleeping message is printed to the console after the JVM exits). This lines up with what's discussed in this question.

So the first thing I'd suggest doing is validating your initial assumption that the subprocess is in fact being killed; perhaps something else is going wrong that causes it to die for another reason. Using .inheritIO() can help debugging, in case the subprocess is generating error messages you're not seeing.


All that said, nohup may not be what you want, as 'that other guy' notes; nohup only causes a process to ignore SIGHUP, and it will still respect other signals, notably SIGINT and SIGTERM (Process.destroy() sends a SIGTERM, for instance). See this question for more.

As with all problems in programming, introducing more layers would probably help :)

Create a shell script that handles the desired disowning logic, e.g.

$ cat start-and-disconnect.sh
#!/bin/bash

# obviously tweak this as necessary to get the behavior you want,
# such as redirecting output or using disown instead of nohup
nohup "$@" & 

The advantage here is that Bash (or whatever shell you prefer) has better process-management control than Java, and now you can test it in isolation, without needing to compile and run your Java application.

Once you're happy with the script, your Java code simply becomes:

new ProcessBuilder("/path/to/start-and-disconnect.sh", "/path/to/your_binary.sh")
    .inheritIO().start().waitFor();

You can safely .waitFor() the call to complete, since start-and-disconnect.sh will exit after starting its subprocess.

dimo414
  • 47,227
  • 18
  • 148
  • 244