12

I'm using this definition for a systemd job:

 [Unit]
 Description=Some job

 [Service]
 ExecStart=/usr/local/sbin/somejob
 User=dlt
 Type=forking

 [Install]
 WantedBy=multi-user.target

The script is called is as follows (calling a simple routine that listens on a tcpip socket and appends the input to a file):

 #!/bin/sh

 cd /home/user/tmp/testout
 nohup java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar </dev/null >/dev/null &

After systemctl start somejob process shows as running, with init as its parent:

 user@CANTANDO ~$ ps -u dlt eo pid,ppid,command
   PID  PPID COMMAND
  8718     1 java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar

After performing systemctl stop somejob the process doesn't show anymore (and the port is closed).

So everything seems fine and dandy

My question is: Is this an acceptable solution for running a java daemon with systemd, or are there caveats, and thus other more stable or secure ways to go about achieving this?

1 Answer 1

18

Here's some minor modifications:

  1. Since it listens on a network socket, make it a dependency of network.target.
  2. nohup is not needed since systemd will daemonize the executable for you.
  3. I think a separate shell script would be an overkill, so just merge it into the service file.
  4. Redirection (< /dev/null and so forth) isn't needed since systemd sets up an appropriate standard I/O context. Indeed, if you take the redirection out systemd will log anything sent to standard output by the Java program in its journal, with no special logging mechanism required.
  5. Running asynchonously from the invoking shell (&) isn't needed or appropriate.
  6. There's a specific behaviour pattern required by Type=forking, and if it isn't followed by the dæmon things go wrong. So try for Type=simple (or Type=notify).

So the service file looks like this:

[Unit]
Description=Some job
After=network.target

[Service]
WorkingDirectory=/home/user/tmp/testout
SyslogIdentifier=SocketTest
ExecStart=/bin/sh -c "exec java -jar /home/user/programming/tests/java/core/SocketTest/SocketTest.jar"
User=dlt
Type=simple

[Install]
WantedBy=multi-user.target

Notes:

  1. You cannot just use java as the name of the program to run. systemd doesn't search PATH for executables, and the name of the executable given to ExecStart must be absolute. So if you want path searching you have to invoke via a shell or /usr/bin/env. We choose /bin/sh here.
  2. Because this is Type=simple the shell must exec Java, not run it as a child process. systemd controls the service through the main process, and that needs to be Java, not a parent shell process.
  3. Because this isn't invoking the Java executable directly, systemd will put the name sh in its journal as the service name. See How to avoid /usr/bin/env being marked in systemd logs as the executable for more on this.

As far as I know, there is no special caveat of running Java application with Systemd.

6
  • 1
    That won't work. Problem 1: This isn't the shell; there are no redirection operators. You don't really want that redirection anyway. Problem 2: ExecStart demands absolute pathnames. Problem 3: unix.stackexchange.com/questions/229523
    – JdeBP
    Commented Nov 1, 2016 at 15:59
  • Nice head up. I can only manage to fix problem 1. How do you go about fixing Prob 2,3? Commented Nov 1, 2016 at 16:07
  • 1
    See the answer as edited.
    – JdeBP
    Commented Nov 1, 2016 at 17:49
  • I don't think the sh is necessary here.
    – faho
    Commented Nov 18, 2016 at 13:02
  • Hello @Yun-ChihChen how do you stop the process. What does ExecStrop would look like? I have been using init.d along with a pid file but found this easier. So I needed to make sure I know how to stop etc. Thanks Commented Mar 16, 2018 at 11:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .