Besoin de lancer un service de façon "safe",
c'est-à-dire avec une capacité de redémarrage
automatique en cas de crash ?
Exemple d'implémentation
La fonction "safe" proposée ici est greffée sur un
script init.d assez standard. Elle a cependant un prérequis :
qu'un fichier "pid file" soit créé par le service
lancé (ou par le script de lancement).
Pour les besoins de l'exemple, le script créé un
simili-service, en l'occurrence un script bash
/usr/local/sbin/aserviced dont la seule capacité consiste
à tenir à jour un fichier /tmp/aserviced.log.
Le code ajouté au titre de la fonction "safe" est mis en
évidence en bleu.
Le code spécifique de création du simili-service est
en gris.
Fichier
/etc/rc.d/init.d/aservice
#!/bin/bash
#
#
aservice Init script for a service
#
#
chkconfig: - 99 01
#
#
description: A service
#
processname: aservice
# config:
/etc/aservice.conf
# pidfile:
/var/run/aservice.pid
# Source
function library.
. /etc/rc.d/init.d/functions
# Service
name
SERVICE=$(basename $0)
# Path to
the actual executable
BINARY=/usr/local/sbin/aserviced
# Process
name
PROCESS=$(basename $BINARY)
# Lock
file name
LOCKFILE=/var/lock/subsys/$SERVICE
# Process
pid file name. Should be created by the executable, otherwise by
start() function
PIDFILE=/var/run/$SERVICE.pid
# Safe process pid file name. Created by
safe() function
PIDFILE_SAFE=/var/run/$SERVICE-safe.pid
RETVAL=0
#
Functions
safe() {
# One safe process is
enough
[ -f $PIDFILE_SAFE ]
&& [ -d /proc/$(cat $PIDFILE_SAFE) ] && exit
safe_eye &
# Store safe process pid
echo $! >$PIDFILE_SAFE
RETVAL=0
}
safe_eye() {
# Safe process. Simple
enough not to crash. Never ends unless killed.
SAFE_PERIOD=5
SAFE_RESTART=10
# Keep an eye on service
and restart when dead
while true; do
sleep
$SAFE_PERIOD
if [ -f
$PIDFILE ] && [ ! -d /proc/$(cat $PIDFILE) ]; then
LOG="Crash detected! re-start $SERVICE"
echo $LOG >&2
logger -p daemon.warn -t $SERVICE $LOG
service $SERVICE start
sleep $SAFE_RESTART
fi
done
}
start() {
# Clean obsolete pid file
[ -f
$PIDFILE ] && [ ! -d /proc/$(cat $PIDFILE) ] && rm
-f $PIDFILE
echo -n
"Starting $SERVICE: "
daemon
--pidfile $PIDFILE $BINARY
RETVAL=$?
echo
[ $RETVAL
-eq 0 ] && touch $LOCKFILE
# Start safe service
service aservice safe
}
stop() {
# Stop safe service
[ -f $PIDFILE_SAFE ]
&& PID_SAFE=$(cat $PIDFILE_SAFE) && rm -f
$PIDFILE_SAFE && kill $PID_SAFE
echo -n
"Stopping $SERVICE: "
killproc -p
$PIDFILE $PROCESS
RETVAL=$?
echo
[ $RETVAL
-eq 0 ] && rm -f $LOCKFILE
}
restart() {
stop
start
}
########################################
# For demo only: create a dummy service
if
[ ! -x $BINARY ]; then
cat >$BINARY <<EOT
#! /bin/bash
# Mini dummy service
# args : -p pidfile
# This demo 'service' forks, creates a pid
file and
# continuously maintains an up-to-date
/tmp/aservice.log file.
# Additionally, it intercepts SIGHUP for a
'reload'-like feature.
do_work() {
trap "echo \$0: SIGHUP caught!" SIGHUP
while true; do
sleep 1
date >/tmp/$PROCESS.log
done
}
# Get arguments
pidfile=/var/run/aservice.pid
# Defaut pid file
while
[ -n "\$1" ]; do
case \$1 in
-p)
pidfile=\$2
shift 2
;;
esac
done
do_work
&
echo
\$! >\$pidfile
echo
-e "\n$0: try to kill process \$! and see what happens."
exit
0
EOT
chmod +x $BINARY
fi
########################################
# Check
that binary is available
[ -x $BINARY ] || exit 5 # LSB (except for status): 5 -
program is not installed
# See how
we were called
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
try-restart|condrestart)
[ -f
$LOCKFILE ] && restart
;;
reload|force-reload)
killproc -p
$PIDFILE $BINARY -HUP
RETVAL=$?
echo
;;
status)
status
$PROCESS -p $PIDFILE
RETVAL=$?
;;
safe)
# 'safe' is
reserved for internal use.
# Keep
using 'start' to start the service
safe
;;
*)
echo
"Usage: $0
{start|stop|restart|try-restart|condrestart|reload|force-reload|status}"
RETVAL=1 # LSB (except for status): 1 -
generic or unspecified error (current practice)
esac
exit $RETVAL
Références :
http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html