Need an init script for a Java service? Like tomcat, liferay, or jboss?
Regular Linux init scripts often don’t work so well. e.g. Java apps typically want to be run by a particular user (e.g. tomcat or liferay). e.g. They may require a ‘special’ shutdown mechanism (e.g. with Tomcat sending a signal to a particular port).
So over the years I have had a handy-dandy script that can control most of my most commonly used Java apps (liferay, tomcat, jboss).
It does things like start up the app as a particular user. Checks to ensure the app is responding on a URL before saying it is stared. Waits for the app to shutdown gracefully, else forces it to quit. And provides kill and killstart commands when you’re developing and just want the thing restarted!
This morning I updated it to use the lsb logging methods. So the output is a bit prettier than the ‘old’ echo’s we used to use.
The current version of the file will live at http://proj.ri.mu/javainitscript
To use it wget that to the /etc/init.d directory on your server. Then rename (or symlink) it to the service you want to control. Currently the tomcat, liferay and jboss names are supported.
Some excerpts (if you’re using the script, alway use the one at http://proj.ri.mu/javainitscript) :
#!/bin/bash
# Startup script for Jakarta Tomcat, Lferay, JBoss, or potentially other java apps
if [ -e /etc/debian_version ]; then
. /lib/lsb/init-functions
elif [ -e /etc/init.d/functions ] ; then
. /etc/init.d/functions
fi
# else we include the crucial log_* methods for lsb-deprived distros
# how long to wait for the app to startup before saying 'its probably up'
STARTWAITTIMES=45
# figure out what to do based on the name of this script
if echo $0 | grep -qai tomcat; then
HOMEDIR=/usr/local/tomcat
TOMCAT_USER=tomcat
APPNAME=Tomcat
elif echo $0 | grep -qai jboss; then
....
else
log_failure_msg "Unknown startup script name $0"
exit 1
fi
# something so we can test if the app is fully started
TESTURL=http://127.0.0.1:8080/
if [ -e $HOMEDIR/initscript/testurl ]; then
TESTURL=$(cat $HOMEDIR/initscript/testurl)
fi
# makes it a bit easier to find if the process is running. e.g. put a -Dsomeval=Y
# into the JAVA_OPTS for the program. e.g. in catalina.sh or setenv.sh or run.conf
if [ -e $HOMEDIR/initscript/grepstring ]; then
GREPSTRING=$(cat $HOMEDIR/initscript/grepstring)
fi
#Necessary environment variables
export JAVA_HOME=/usr/java/jdk
#export LD_KERNEL_ASSUME="2.2.5"
if [ "$APPNAME" = "Tomcat" -o "$APPNAME" = "Liferay" -o "$APPNAME" = "Alfresco" ]; then
export CATALINA_HOME=$HOMEDIR
INITSCRIPT=$HOMEDIR/bin/catalina.sh
RUNCOMMAND="export CATALINA_HOME=$CATALINA_HOME; $INITSCRIPT start"
STOPCOMMAND="$INITSCRIPT stop"
STARTGREPTEXT="[o]rg.apache.catalina.startup.Bootstrap start"
LOGFILE=$HOMEDIR/logs/catalina.out
elif [ "$APPNAME" = "JBoss" ]; then
....
else
log_failure_msg "Only JBoss and Tomcat are recognised. Not $APPNAME"
exit 1
fi
setpslist() {
PSLIST=$(ps a --width=1000 --User "$TOMCAT_USER" -o pid,user,command | grep "$GREPSTRING" | grep -v PID | awk '{printf $1 " "}')
}
start() {
setpslist
log_daemon_msg "Starting" "$APPNAME"
if [ ! -z "$PSLIST" ]; then
log_warning_msg "$APPNAME already running, can't start it"
log_end_msg 1
return 1
fi
chown -R $TOMCAT_USER $HOMEDIR
exec su - -p --shell=/bin/sh $TOMCAT_USER -c "cd $(dirname $INITSCRIPT); $RUNCOMMAND >\"$LOGFILE\"" 2>&1 &
local starttime=$(date +"%s")
# wait a bit for the app to start up
while true; do
sleep 3
local now=$(date +"%s")
if wget --tries=1 --timeout=1 --server-response -O - $TESTURL 2>&1 | grep -qai " HTTP/1.1 "; then
log_end_msg 0
break
fi
# process not starting (cf. http response not happening)
if [ $(($now - 15 )) -gt $starttime ]; then
setpslist
if [ -z "$PSLIST" ]; then
log_failure_msg "Java process not starting. Last few lines from the startup log follow:"
log_failure_msg "$(tail -n 4 $LOGFILE)"
log_end_msg 1
return 1
fi
fi
if [ $(($now - $STARTWAITTIMES)) -gt $starttime ]; then
log_warning_msg "$APPNAME startup taking too long, not getting a response on $TESTURL, giving up"
log_end_msg 0
return 0
fi
log_progress_msg .
done
}
killprocesses() {
log_daemon_msg "Killing" "$APPNAME"
setpslist
if [ -z "$PSLIST" ]; then
log_progress_msg "$APPNAME not running, no need to kill it"
log_end_msg 0
fi
kill -9 $PSLIST
log_end_msg 0
}
stop() {
log_daemon_msg "Stopping" "$APPNAME"
setpslist
if [ -z "$PSLIST" ]; then
log_progress_msg "$APPNAME not running, no need to stop it"
log_end_msg 0
fi
waslistening=N
needtokill=N
if wget --tries=1 --timeout=1 --server-response -O - $TESTURL 2>&1 | grep -qai " HTTP/1.1 "; then
waslistening=Y
fi
suoutput=$(su - --shell=/bin/bash -p $TOMCAT_USER -c "$STOPCOMMAND" 2>&1)
local starttime=$(date +"%s")
# wait a while for the app to shutdown gracefully, else kill it
while true; do
sleep 3
local now=$(date +"%s")
setpslist
if [ -z "$PSLIST" ]; then
log_end_msg 0
return 0
fi
if echo $suoutput | egrep -qai "(Refused|Address already in use)" ; then
log_warning_msg "'stop' signal refused, killing $APPNAME."
kill -SIGTERM $PSLIST
elif [ $(($now - 50)) -gt $starttime ]; then
log_warning_msg "Graceful shutdown taking too long, terminating it.";
kill -SIGTERM $PSLIST
elif [ $(($now - 50)) -gt $starttime ]; then
log_warning_msg "Graceful shutdown taking too long, killing it.";
kill -SIGKILL $PSLIST
elif [ "$needtokill" = "Y" ]; then
log_progress_msg "Killing. "
kill -SIGKILL $PSLIST
elif [ "$waslistening" = "Y" -a "$needtokill" = "N" ]; then
if ! wget --tries=1 --timeout=1 --server-response -O - $TESTURL 2>&1 | grep -qai " HTTP/1.1 " ; then
log_progress_msg "Stopped listening on http, but not shutting down fully. "
needtokill=Y
sleep 10
fi
fi
# echo -n $(echo $PSLIST | wc -w) " "
done
}
status() {
setpslist
if [ ! -z "$PSLIST" ]; then
local MSG="$APPNAME ( PIDs $PSLIST ) is running."
if wget --tries=1 --timeout=1 --server-response -O - $TESTURL 2>&1 | grep -qai " HTTP/1.1 "; then
log_success_msg "$MSG And listening on $TESTURL."
else
log_warning_msg "$MSG But not responding on $TESTURL."
fi
else
log_failure_msg "$APPNAME is not running"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 3
start
;;
kill)
killprocesses
;;
killstart)
killprocesses
start
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status|kill|killstart}"
exit 1
esac
exit $?
3 responses to “One Java init script to rule them all”
This sounds like a good idea, but before I can spend time evaluating whether it does what I need, I need to know if I can actually use it. Could you add a FOSS license to it? Apache 2.0 or BSD style would make it easy for anyone to use, and provide some protection for you by declaring it as-is use at your own risk etc….
Heya Gus, anything we provide is free for use of any kind, there is no license at all, just take it and do what you want with it.
[…] lunch, I promptly searched for this legendary script. My search lead me to the One Java init script to rule them all, which is an init script for Java application servers (E.g. Tomcat and JBoss) that will work on […]