Run a Java Application as a Service on Linux - java

I have written a Java server application that runs on a standard virtual hosted Linux solution. The application runs all the time listening for socket connections and creating new handlers for them. It is a server side implementation to a client-server application.
The way I start it is by including it in the start up rc.local script of the server. However once started I do not know how to access it to stop it and if I want to install an update, so I have to restart the server in order to restart the application.
On a windows PC, for this type of application I might create a windows service and then I can stop and start it as I want. Is there anything like that on a Linux box so that if I start this application I can stop it and restart it without doing a complete restart of the server.
My application is called WebServer.exe. It is started on server startup by including it in my rc.local as such:
java -jar /var/www/vhosts/myweb.com/phpserv/WebServer.jar &
I am a bit of a noob at Linux so any example would be appreciated with any posts. However I do have SSH, and full FTP access to the box to install any updates as well as access to a Plesk panel.

I wrote another simple wrapper here:
#!/bin/sh
SERVICE_NAME=MyService
PATH_TO_JAR=/usr/local/MyProject/MyJar.jar
PID_PATH_NAME=/tmp/MyService-pid
case $1 in
start)
echo "Starting $SERVICE_NAME ..."
if [ ! -f $PID_PATH_NAME ]; then
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
echo $! > $PID_PATH_NAME
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is already running ..."
fi
;;
stop)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stoping ..."
kill $PID;
echo "$SERVICE_NAME stopped ..."
rm $PID_PATH_NAME
else
echo "$SERVICE_NAME is not running ..."
fi
;;
restart)
if [ -f $PID_PATH_NAME ]; then
PID=$(cat $PID_PATH_NAME);
echo "$SERVICE_NAME stopping ...";
kill $PID;
echo "$SERVICE_NAME stopped ...";
rm $PID_PATH_NAME
echo "$SERVICE_NAME starting ..."
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
echo $! > $PID_PATH_NAME
echo "$SERVICE_NAME started ..."
else
echo "$SERVICE_NAME is not running ..."
fi
;;
esac
You can follow a full tutorial for init.d here and for systemd (ubuntu 16+) here
If you need the output log replace the 2
nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
lines for
nohup java -jar $PATH_TO_JAR >> myService.out 2>&1&

A simple solution is to create a script start.sh that runs Java through nohup and then stores the PID to a file:
nohup java -jar myapplication.jar > log.txt 2> errors.txt < /dev/null &
PID=$!
echo $PID > pid.txt
Then your stop script stop.sh would read the PID from the file and kill the application:
PID=$(cat pid.txt)
kill $PID
Of course I've left out some details, like checking whether the process exists and removing pid.txt if you're done.

Linux service init script are stored into /etc/init.d. You can copy and customize /etc/init.d/skeleton file, and then call
service [yourservice] start|stop|restart
see http://www.ralfebert.de/blog/java/debian_daemon/. Its for Debian (so, Ubuntu as well) but fit more distribution.

Maybe not the best dev-ops solution, but good for the general use of a server for a lan party or similar.
Use screen to run your server in and then detach before logging out, this will keep the process running, you can then re-attach at any point.
Workflow:
Start a screen: screen
Start your server: java -jar minecraft-server.jar
Detach by pressing: Ctl-a, d
Re-attach: screen -r
More info here: https://www.gnu.org/software/screen/manual/screen.html

Another alternative, which is also quite popular is the Java Service Wrapper. This is also quite popular around the OSS community.

Referring to Spring Boot application as a Service as well, I would go for the systemd version, since it's the easiest, least verbose, and best integrated into modern distros (and even the not-so-modern ones like CentOS 7.x).

The easiest way is to use supervisord. Please see full details here: http://supervisord.org/
More info:
https://askubuntu.com/questions/779830/running-an-executable-jar-file-when-the-system-starts/852485#852485
https://www.digitalocean.com/community/tutorials/how-to-install-and-manage-supervisor-on-ubuntu-and-debian-vps

Here is a sample shell script (make sure you replace the MATH name with the name of the your application):
#!/bin/bash
### BEGIN INIT INFO
# Provides: MATH
# Required-Start: $java
# Required-Stop: $java
# Short-Description: Start and stop MATH service.
# Description: -
# Date-Creation: -
# Date-Last-Modification: -
# Author: -
### END INIT INFO
# Variables
PGREP=/usr/bin/pgrep
JAVA=/usr/bin/java
ZERO=0
# Start the MATH
start() {
echo "Starting MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "The service is already running"
else
#Run the jar file MATH service
$JAVA -jar /opt/MATH/MATH.jar > /dev/null 2>&1 &
#sleep time before the service verification
sleep 10
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Service was successfully started"
else
echo "Failed to start service"
fi
fi
echo
}
# Stop the MATH
stop() {
echo "Stopping MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
#Kill the pid of java with the service name
kill -9 $($PGREP -f MATH)
#Sleep time before the service verification
sleep 10
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Failed to stop service"
else
echo "Service was successfully stopped"
fi
else
echo "The service is already stopped"
fi
echo
}
# Verify the status of MATH
status() {
echo "Checking status of MATH..."
#Verify if the service is running
$PGREP -f MATH > /dev/null
VERIFIER=$?
if [ $ZERO = $VERIFIER ]
then
echo "Service is running"
else
echo "Service is stopped"
fi
echo
}
# Main logic
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|reload)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
exit 1
esac
exit 0

From Spring Boot application as a Service, I can recommend the Python-based supervisord application. See that stack overflow question for more information. It's really straightforward to set up.

Other answers do a good job giving custom scripts and setups depending on your platform. In addition to those, here are the mature, special purpose programs that I know of:
JSW from TanukiSoftware
YAJSW is an open source clone from the above. It is written in Java, and it is a nanny process that manages the child process (your code) according to configurations. Works on windows / linux.
JSVC is a native application. Its also a nanny process, but it invokes your child application through the JNI, rather than as a subprocess.

You can use Thrift server or JMX to communicate with your Java service.

From Spring Boot Reference Guide
Installation as an init.d service (System V)
Simply symlink the jar to init.d to support the standard start, stop, restart and status commands.
Assuming that you have a Spring Boot application installed in /var/myapp, to install a Spring Boot application as an init.d service simply create a symlink:
$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp
Once installed, you can start and stop the service in the usual way. For example, on a Debian based system:
$ service myapp start
If your application fails to start, check the log file written to /var/log/<appname>.log for errors.
Continue reading to know how to secure a deployed service.
After doing as written I've discovered that my service fails to start with this error message in logs: start-stop-daemon: unrecognized option --no-close. And I've managed to fix it by creating a config file /var/myapp/myapp.conf with the following content
USE_START_STOP_DAEMON=false

It is possible to run the war as a Linux service, and you may want to force in your pom.xml file before packaging, as some distros may not recognize in auto mode. To do it, add the following property inside of spring-boot-maven-plugin plugin.
<embeddedLaunchScriptProperties>
<mode>service</mode>
</embeddedLaunchScriptProperties>
Next, setup your init.d with:
ln -s myapp.war /etc/init.d/myapp
and you will be able to run
service myapp start|stop|restart
There are many other options that you can find in Spring Boot documentation, including Windows service.

Im having Netty java application and I want to run it as a service with systemd. Unfortunately application stops no matter of what Type I'm using. At the end I've wrapped java start in screen. Here are the config files:
service
[Unit]
Description=Netty service
After=network.target
[Service]
User=user
Type=forking
WorkingDirectory=/home/user/app
ExecStart=/home/user/app/start.sh
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
start
#!/bin/sh
/usr/bin/screen -L -dmS netty_app java -cp app.jar classPath
from that point you can use systemctl [start|stop|status] service.

To run Java code as daemon (service) you can write JNI based stub.
http://jnicookbook.owsiak.org/recipe-no-022/
for a sample code that is based on JNI. In this case you daemonize the code that was started as Java and main loop is executed in C. But it is also possible to put main, daemon's, service loop inside Java.
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029
Have fun with JNI!

However once started I don't know how to access it to stop it
You can write a simple stop script that greps for your java process, extracts the PID and calls kill on it. It's not fancy, but it's straight forward.
Something like that may be of help as a start:
#!/bin/bash
PID = ps ax | grep "name of your app" | cut -d ' ' -f 1
kill $PID

Related

Stop Java from killing Bash script that started it

I've spent the past couple days working on this, and at this point I am super stuck. I have a Java program that must be run not as a service. This program must also be capable of updating itself when a new file is given for updating.
As a result, I have a script that is started with Linux that starts the Java application and then checks every 5 seconds if the application has been terminated. If the application has been terminated, it should check if there is an update and then start appropriately.
This is the code for that script:
#!/bin/bash
JAVA_HOME=/usr/lib/jvm/java-16-openjdk-amd64
WORKING_DIR=~/Data
LOG=$WORKING_DIR/logs/Bash.log
rm $LOG
echo "Script started" > $LOG
while true; do
source $WORKING_DIR/Server.pid
if ! kill -0 $AppPID; then
echo "App must be started" >> $LOG
source $WORKING_DIR/UpdateStatus
if [ "$UpdateReady" -eq "1" ]; then
echo "Moving files for update" >> $LOG
mv $WORKING_DIR/Server.jar $WORKING_DIR/old.jar
mv $WORKING_DIR/new.jar $WORKING_DIR/Server.jar
fi
nohup ${JAVA_HOME}/bin/java -jar ${WORKING_DIR}/Server.jar &
echo AppPID="$!" > $WORKING_DIR/Server.pid
echo "Server started" >> $LOG
if [ "$UpdateReady" -eq "1" ]; then
echo "Checking for safe update" >> $LOG
source $WORKING_DIR/Server.pid
echo UpdateReady="0" > $WORKING_DIR/UpdateStatus
sleep 5;
if kill -0 $AppPID; then
echo "Update successful" >> $LOG
rm $WORKING_DIR/old.jar
else
echo "Update failed, restarting old jar" >> $LOG
rm $WORKING_DIR/Server.jar
mv $WORKING_DIR/old.jar $WORKING_DIR/Server.jar
nohup ${JAVA_HOME}/bin/java -jar ${WORKING_DIR}/Server.jar &
echo AppPID="$!" > $WORKING_DIR/Server.pid
fi
fi
echo "Server start process finished, going into idle state" >> $LOG
fi
sleep 5
echo "5 seconds idle passed" >> $LOG
done
To initialize the update, I have tried a couple of different things, both with the same result. First I had set UpdateReady="1" through Java, then used exit(0);. I have also tried having Java call a Bash script which also sets UpdateReady="1" but uses kill $AppPID to shutdown the java application.
The result is that both the Java application and the Bash script stop executing causing the update and restart to fail! I have looked through a significant amount of Stack Overflow questions and answers finding things such as nohup, all to no avail.
I will once again state that the Java application cannot be run as a service. No packages other than what is included in Java or made by Apache can be used, and no programs can be installed to Linux. I would prefer to solve the problem with Bash.
Upon testing some things mentioned in comments, I may have missed something that turns out to be important. While all other runs of the startup script will be run by the startup applications manager, the initial run is not.
The install is taken care of remotely with an SSH connection sending the following command string:
cd /home/UserName; unzip -u -o Server.zip; chmod 777 install.sh; bash install.sh &; exit
install.sh is as follows:
#!/bin/bash
INSTALL_DIR=~/Data
mkdir ${INSTALL_DIR}
mkdir ${INSTALL_DIR}/logs
mkdir ${INSTALL_DIR}/data
cp Server.jar ${INSTALL_DIR}/Server.jar
cp service-start.sh ${INSTALL_DIR}/service-start.sh
chmod 777 ${INSTALL_DIR}/service-start.sh
rm Server.jar
rm service-start.sh
rm Server.zip
nohup bash $INSTALL_DIR/service-start.sh &
Upon rebooting my machine, I noticed that this problem goes away! This means that there must be a problem with the initial setup script. When the shell command is run, it does seem to be sticky and not actually let go after the bash install.sh &. I have tried putting nohup at the beginning of this, however the entire line will not run in that case for reasons I am not able to determine.
I would prefer to not have the user be forced to restart after install and can't seem to find any way to force the Startup Application manager to start an application at any time other than startup.
Well, after a lot of searching and some prompting from the comments, I found that the issue lied with how the program was initially being started.
As mentioned in the update, the first run is always started by an ssh connection. I knew there was a slight problem with this ssh connection, as it seemed to hold onto the connection no matter what I did. It turns out that this was causing the problem that resulted in the Bash instance and the Java instance remaining attached.
The solution for this problem was found here: jsch ChannelExec run a .sh script with nohup "lose" some commands
After managing to get the initial setup to start with nohup properly, the issue has gone away.

Ansible terminates my app with "nohup"

I have a task in Ansible playbook that executes a .jar file in the background, but after finishing that task, the (java) app terminates.
- name: Run Java app in the background
shell: nohup java -jar app.jar &
I need the app running for tasks further down in the playbook. Any ideas??
NOTE: When I run it in Putty ssh session it runs smoothly and the app stays in background.
The most likely reason is attached IO. Try:
- name: Run Java app in the background
shell: nohup java -jar app.jar </dev/null >/dev/null 2>&1 &
Ok So I had this issue today and my script is a tad different but essentially doing the same thing so this is what I have, running on Oracle, Centos and RHEL.
in script start_service.sh I have this, this script is executed not sourced.
#!/bin/sh
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
nohup java -jar ${DIR}/$1 --spring.config.location=${DIR}/application.yml --logging.config=${DIR}/logging.xml > ${DIR}/log/output.log 2>&1 &
In my playbook I have:
- name: run service
shell: "{{ service_install_location }}/application_name/start-service.sh application_name-{{ application_version }}.jar"
args:
chdir: "{{ service_install_location }}/application_name"
executable: /bin/bash
Now, the BASH_SOURCE argument is specific to bash so if you are running plain old sh then you need $0. nohup is required so when the ssh connection terminates your background task does not get killed (turn on -vvv for ansible to see connections being made to understand how this happens on a remote machine).
I should point out we are doing this temporarily as this should really be installed as a service to be under the control of service/init.d but for now, this answers your question

How to restart a Jar file on init.d?

I am using CentOS 6.3 64bit.
I am using starting my server as a service.
#!/bin/sh
# chkconfig: 2345 90 10
#description: URL Server
# processname: urlovedserver
start(){
java -jar /root/BookkServer-0.0.1-jar-with-dependencies.jar
}
# See how we were called.
case "$1" in
start)
start
;;
*)
echo "Usage: $0 {start}"
exit 1
esac
What should I add to the script so that it responds to "service urlovedserver restart"? I can't get how to stop a java service.
Write PID in file. When you want you can read PID-file for kill java process.
start(){
#run your process in background
java -jar /root/BookkServer-0.0.1-jar-with-dependencies.jar &
# write PID
echo $! > program.pid
}
Now you can kill process:
kill -9 `cat program.pid` #kill java process
One idea would be to get the pid of the executed command (use the $! shell variable) save it in a file and then add a stop command in your shell script that just kills the java process that it reads from the previous file. Something like
kill -9 `cat /var/run/myjavaservice.pid`.
Then restart will be just stop() and start()

JSVC initscript doesn't exit

I'm trying to deamonize my Java app using jsvc. This is my initscript
#!/bin/sh
# CONFIG
JSVC=/opt/jsvc/jsvc
JAVA_HOME=/usr/lib/jvm/jre-1.6.0-openjdk.x86_64
USER=gserv
ARGS=none
# END CONFIG
PIDFILE=/var/run/silvercar-gameserver.pid
LOGDIR=/var/log/silvercar-gameserver
case "$1" in
start)
export JAVA_HOME
cd `dirname $0`
$JSVC -jvm server -pidfile $PIDFILE -user $USER -outfile $LOGDIR/stdout -errfile $LOGDIR/stderr \
-cp `cat classpath` tr.silvercar.gameserver.runner.DeamonGameServer $ARGS
;;
stop)
$JSVC -stop -pidfile $PIDFILE
;;
esac
exit 0
When I run ./thisscript.sh start as root two things go wrong, and I suspect they're related:
The app starts, but its output is shown instead of saved to the specified outfile
The script doesn't exit, but blocks until I hit Ctrl+C.
What am I doing wrong?
I don't see anything wrong in your launch script; perhaps there is an issue in your service implementation DeamonGameServer. Try replacing your class with a simple Daemon skeleton implementation and see what happens.
Also, note there is an open defect in jsrv : Jsvc does not exit when all non-daemon threads are dead.

Start java process at boot and auto-restart on death

I have two requirements for my Java app. If it dies, restart it. If the server reboots, restart it - simple enough. Using the answer here I have a script that will restart when the java application dies.
#!/bin/bash
until java -Xms256m -Xmx768m -jar MyApp.jar; do
echo "MyApp crashed with exit code $?. Respawning... " >&2
sleep 5
done
I can run this with "nohup restart_script.sh &" and it will run all day long without issue. Now for the startup requirement. I took the /etc/init.d/crond script and replaced the crond binary with my script but it hangs on startup.
#!/bin/bash
#
# Init file for my application.
#
. /etc/init.d/functions
MYAPP=restart_script.sh
PID_FILE=/var/run/myapp.pid
start(){
echo -n "Starting My App"
daemon --user appuser $MYAPP
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/myapp
return $RETVAL
}
stop(){
echo -n "Stopping my application"
killproc $MYAPP
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/myapp
return $RETVAL
}
...
case "$1" in
start)
start
;;
stop)
stop
;;
...
esac
When I run /sbin/service myapp start the script starts but hangs the console. I have tried "daemon --user appuser nohup $MYAPP &" and I am immediately returned to the prompt without any [OK] indication and when I do a ps, I still see that the init is hung. Any ideas how to call a script within the init script and get it to return properly?
Thanks,
Greg
The daemon function on my machine (old RedHat) does not return until the executed program returns. So you are going to need to have your little utility script do the forking.
Try writing your utility like this:
#!/bin/bash
(
until java -Xms256m -Xmx768m -jar MyApp.jar; do
echo "MyApp crashed with exit code $?. Respawning... " >&2
sleep 5
done
) &
How this works. Putting a command in parentheses starts code running in a new process. You put the process in the background so the original process will return without waiting for it.
You need a java service wrapper, here is a very good one... tanuki
I mean to say, you don't need to reinvent the wheel, there are tools out there..

Categories