Tuesday, January 5, 2016

Running a Java Program as a daemon (Background service) on *nix systems

How to run a Java Program as a daemon (Background service) on *nix systems?

Ever needed to run a Java program as a daemon (background service) on your *nix server? All you want is to run some basic operations such as start/stop/restart? then are not a lone.


If you google around for sometime, you will be able to find one or more of the following options:

  • Java Service Wrapper.
  • Apache Jakarta Commons Daemon package (Jsvc).
  • Write your own custom shell script.

The first two options are much more advanced and you can do a lot more by using them. However, they come with some complexities such as compatibility issues, having the need to implement custom interfaces, or that it requires installation of some extra packages before using. A shell script, on the other hand, is easier to adapt to changing OS and Java environments.

So I decided to spend sometime to write a shell script that can be use as template for managing any java program. So I came up with SJSWS (Simple Java Service Wrapper Script).

Basically, SJSWS is a simple tool to generate a custom shell script to manage any java program as a service (Start/Stop/restart/etc…). For the full details about the tool and how generate your own, you follow the example described in the SJSWS git repo.

For now the tool simply reads pre-configured values from a property file (Service.properties) and inject them into template (ServiceTemplate.sh) to generate script customized to run a specific service.

However, since the tool is doing some basic tasks for now (read values and feed them into a template file ), you have the options to manually do that. Here what the ServiceTemplate.shlooks like today:

#!/bin/sh
 ### BEGIN INIT INFO
 # Provides:          V_SERVICE_NAME
 # Required-Start:    $local_fs $remote_fs $network $syslog
 # Required-Stop:     $local_fs $remote_fs $network $syslog
 # Default-Start:     2 3 4 5
 # Default-Stop:      0 1 6
 # X-Interactive:     true
 # Short-Description: Start/stop/restart/etc.. service wrapper to run java program as deamon.
 ### END INIT INFO
 # author:            Suleiman Alrosan
 # version:            v0.1

SERVICE_NAME=V_SERVICE_NAME
SERVICE_WORK_DIR=V_SERVICE_WORK_DIR
SERVICE_PID_FILE=V_SERVICE_PID_FILE
SERVICE_CLASS_PATH=V_SERVICE_CLASS_PATH
SERVICE_CLASS=V_SERVICE_CLASS
SERVICE_CMD=V_SERVICE_CMD

get_conf()
{
 
 echo "
 --------------------------------------- \033[7mService Configuration\033[0m ---------------------------------------
 The following list represent the service configurations:  
 -\033[1mSERVICE_NAME\033[0m: $SERVICE_NAME
 -\033[1mSERVICE_WORK_DIR\033[0m: $SERVICE_WORK_DIR
 -\033[1mSERVICE_PID_FILE\033[0m: $SERVICE_PID_FILE
 -\033[1mSERVICE_CLASS_PATH\033[0m: $SERVICE_CLASS_PATH
 -\033[1mSERVICE_CLASS\033[0m: $SERVICE_CLASS
 -\033[1mSERVICE_CMD\033[0m:  $SERVICE_CMD
 ------------------------------------------------------------------------------------------------------------
 "
}

do_start()
{
 echo "Starting $SERVICE_NAME service ..."
 #nohup java -cp $SERVICE_CLASS_PATH $SERVICE_CLASS  $SERVICE_WORK_DIR 2>> /dev/null >> /dev/null &
 nohup $SERVICE_CMD  $SERVICE_WORK_DIR 2>> /dev/null >> /dev/null & 
 echo $! > $SERVICE_PID_FILE
 PID=$(cat $SERVICE_PID_FILE);
 echo "$SERVICE_NAME service started with PID[$PID]..."
}

do_stop()
{
 PID=$(cat $SERVICE_PID_FILE);
 echo "Stopping $SERVICE_NAME service with PID[$PID]..."
 kill $PID;
 echo "$SERVICE_NAME stopped ..."
 rm $SERVICE_PID_FILE
}

do_restart()
{
 do_stop
 do_start
}

get_status()
{
 if [ ! -f $SERVICE_PID_FILE ]; then
  echo "$SERVICE_NAME service is not running"
 else
  PID=$(cat $SERVICE_PID_FILE);
  echo "$SERVICE_NAME service is running on PID[$PID]"
 fi
}

get_pid(){
 if [ ! -f $SERVICE_PID_FILE ]; then
  echo "NO ACTIVE PID"
 else
  PID=$(cat $SERVICE_PID_FILE);
  echo "PID: $PID"
 fi
}

print_help()
{
 echo '
 --------------------------  \033[7mSimple Java Service Wrapper Script(SJSWS)\033[0m -----------------------------
 This is a simple script to manage java programs(Start/stop/restart/etc.. ), which can be setup as deamon(background service).
 The script accepts the following commands:
 
 - \033[1mh,help\033[0m: print information about the scrip.  

 - \033[1mconf\033[0m: print the current configuration values for the service. 

 - \033[1mst, status\033[0m: print the current status of the service. 

 - \033[1mstart\033[0m: start the service by executing the configured java command.   

 - \033[1mstop\033[0m: stop the service by killing the PID.

 - \033[1mrestart\033[0m: restart the configured service by stopping and then starting the service again. 
 
 - \033[1mpid\033[0m: print the PID for service.
 '
}

case $1 in
 h)
  print_help
 ;;
 help)
  print_help
 ;;
 pid)
  get_pid
 ;;
 conf)
  get_conf
 ;;
 st)
  get_status
 ;;
 status)
  get_status
 ;;
 start)
  if [ ! -f $SERVICE_PID_FILE ]; then
   do_start
  else
   echo "$SERVICE_NAME service is already running."
  fi
 ;;
 stop)
  if [ -f $SERVICE_PID_FILE ]; then
   do_stop
  else
   echo "$SERVICE_NAME service is already stopped."
  fi
 ;;
 restart)
  if [ -f $SERVICE_PID_FILE ]; then
   do_restart
  else
   echo "$SERVICE_NAME service is not running. Start the service first."
  fi
 ;;
 *)  
  echo "Invalid command. See help for more information." 
 ;; 
esac

All you need to do is to replace the values that start with “V_”, with values that is specific to your program. Here is the description for each variable:

Property Name Description
SERVICE_NAME The name of your service without any spaces
SERVICE_WORK_DIR The location to the dir where your jar file is located.
SERVICE_PID_FILE File name with full path that the service will use to store the process ID. The default is $SERVICE_WORK_DIR"/"$SERVICE_NAME"_pid"
SERVICE_CLASS_PATH Path to your jars
SERVICE_CLASS Full class name that has the main method for your java program
SERVICE_CMD The actual command that the final script will execute to start your service. Default is “java -cp $SERVICE_CLASS_PATH $SERVICE_CLASS”

Once you have your script ready, all you need to do is set it up as service. This step might be different from Linux system to another. Here is how it works Ubuntu 14.04.3 LTS :

 # sudo cp output/service.sh /etc/init.d/myJavaService
 # sudo chmod +x /etc/init.d/myJavaService 
 # sudo update-rc.d myJavaService defaults 

That’s it!!! Now you have myJavaService setup as a daemon. You can start, stop, get the status and PID for your service :

 # /etc/init.d/myJavaService start
 # /etc/init.d/myJavaService st
 # /etc/init.d/myJavaService pid
 # /etc/init.d/myJavaService restart
 # /etc/init.d/myJavaService stop
 # /etc/init.d/myJavaService conf
 # /etc/init.d/myJavaService help

1 comment:

Generate a unique N letters word sequence (by using relationship between Factoradic base system and Lexicographic Permutation Order of a String)

Lets say that you want to generate a unique 3 letters code sequence to be used as a primary key for some data recodes. Also let assume ...