Gressil uses jnr-ffi to provide
daemonization and "forking" for Java processes. It uses
posix_spawn
to achieve this, rather than
fork
and exec
. Spawn is used, rather than
the standard C world idiom of fork
followed by
exec
as fork
is very unsafe on the JVM --
there is no such thing as a critical section which cannot get splatted
by GC reshuffling pointers. Here, the child process is started by spawning
a new process complete with command line, not by forking the state of the
parent process.
Usage for daemonization looks like:
package org.skife.gressil.examples;
import org.skife.gressil.Daemon;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import static org.skife.gressil.Daemon.remoteDebugOnPort;
public class ChattyDaemon
{
public static void main(String[] args) throws IOException
{
new Daemon().withMainArgs(args)
.withPidFile(new File("/tmp/chatty.pid"))
.withStdout(new File("/tmp/chatty.out"))
.withExtraMainArgs("hello", "world,", "how are you?")
.withExtraJvmArgs(remoteDebugOnPort(5005))
.daemonize();
while (!Thread.currentThread().isInterrupted()) {
System.out.println(new Date() + " " + Arrays.toString(args));
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
In the parent process the call to Daemon#daemonize()
will
call System.exit()
, in the child process it will return
normally.
The child process, in this case, will also wait for a Java debugger to
attach on port 5005. It will attach stdout to /tmp/chatty.out
,
and stdin and stderr will default to /dev/null
(which stdout would also attach to
by default if it were not specified).
The easiest way to get started is via maven:
<dependency>
<groupId>org.skife.gressil</groupId>
<artifactId>gressil</artifactId>
<version>0.0.4</version>
</dependency>