3

I have a script to start java application on boot time.

[Unit]
Description=test Background

[Service]
ExecStart=/bin/bash -c "/usr/bin/java -jar /var/www/tset.com/*.jar"
Type=simple
WorkingDirectory=/var/www/test.com

[Install]
WantedBy=multi-user.target

Can we edit this to write pid into a file in specific location?

As an example,

ExecStart=/bin/bash -c "/usr/bin/java -jar /var/www/test.com/*.jar | echo $! > ${RUNNING_PID}"
Janith
  • 399

3 Answers3

4

You should be able to run java directly rather than running a bash shell that runs java. If you do that you can run the systemctl show command to get the PID

systemctl show -p MainPID <your service name>

assuming of course that your java application doesn't create more processes.

If your service name file ends in .service then you can omit the .service suffix from <your service name>

If you run via a bash script then you'll get the pid of the bash shell that's running your java process.

3

The way I'd approach this problem is this way:

ExecStart=/bin/bash -c 'echo $$ > /var/run/tset.pid; exec /usr/bin/java -jar /var/www/tset.com/*.jar'

There's a couple things that require attention:

  • what you're trying to do is to write .pid file which contains the PID of the process, and on Linux the "de facto" location is to put it into /var/run

  • The > operator is for redirecting stdout of echo, which will be the contents of $$ or the shell PID.

  • Why shell PID ? Well, that's because next thing we're using is exec command which will replace shell process with your java application. What was PID 1234 representing shell will now be 1234 representing java application.

Such approach, while seems convoluted, is actually more appropriate:

  • we know the PID instead of using ps or pgrep to find it, we don't have to apply complex parsing, nor we have a problem if there's multiple instances of the application running already ( which shouldn't be the case if you're using a systemd service to start it, but there's no harm in accounting for a possibility of that as well )
  • and with exec resources won't be wasted for starting multiple processes. When you have something like bash -c '/usr/bin/java -jar myapp.jar & pgrep -f myapp.jar > /var/run/myapp.pid ' that's 3 processes. In the above command suggested - we have one process replacing another.

Of course, this is just an example. Adjust how necessary to your case, and /var/run/tset.pid is chosen here just as an example - naming is up to you as well as location of the file, though I'd recommend using /var/run for consistency with other applications.

Side note:

The | echo $! > ${RUNNING_PID}" part wouldn't be appropriate for at least one reason: ${RUNNING_PID} is a variable, however it is not declared anywhere, so it would be a replaced by plank in shell. | is pointless - stdout of java application is connected to stdin of echo which in case where you want output of application sent to another application is appropriate, but echo does not read stdin - i.e. here it is pointless.

Of course, if the application itself ( i.e. the java application ) forks - i.e creates - another process the $$ won't help much, though to be perfectly fair if the application does indeed create multiple forks then it probably should be the job of the application itself to create and manage the .pid file and report main process pid.

1

systemd leaves your process's pid on enviroment, so you can use it on your script:

    [Unit]

    [Service]
    ExecStart=/home/blah/my-process.sh
    ExecStop=/bin/kill -HUP $MAINPID
    PIDFile=/home/blah/blah.pid

    [Install]
LottaLava
  • 119