Supervizovaný FreeBSD rc.d script pre Go daemon-a

V tomto krátkom blogu vám ukážem ako vytvoriť rc.d script pre Go program, ktorý má bežať na pozadí ako daemon. A aby to bolo zaujímavejšie, tento daemon bude supervizovaný, t.j. v prípade, že z nejakého dôvodu príde k ukončeniu programu (napr. chybou), bude Go program znovu spustený.

Ingrediencie

Na úvod odporúčam prečítať si (excelentnú) dokumentáciu k FreeBSD rc.d scriptingu. FreeBSD rc.d script je spravidla veľmi jednoduchý /bin/sh script. To čo umožňuje rc.d scriptom zostať jednoduchými je rc.subr framework, ktorý sa postará o zložité veci, ako napr. riadenie závislostí medzi rc.d scriptami.

So samotným rc.subr vystačíme v majorite prípadov, my ale chceme daemon-a supervízovať, siahneme preto ešte po daemon utilite, ktorá nám to umožní.

rc.d script

Pozrime sa na ukážkový rc.d script. Keďže používame /usr/sbin/daemon utilitu na manažovanie životného cyklu daemon-a, nemôžeme sa spolahnúť na rc.subr, jeho mechanizmus vytvorenia pid súboru a procedúr start, stop a status. Tieto 3 obslužné procedúry si musíme napísať sami.

Jadrom rc.d scriptu je procedúra goprogram_start a /usr/sbin/daemon -P ${pidfile} -r -f -u $goprogram_user $command, kde je povedané, že chceme vytvoriť rodičovský pid súbor (prepínač -P /var/run/goprogram.pid), pri skončení goprogram ho chceme reštartovať (prepínač -r) a chceme, aby bežal pod používateľom goprogram (prepínač -u goprogram). Procedúry goprogram_stop a goprogram_status musia používať vytvorený pid súbor.

#!/bin/sh
#
# PROVIDE: goprogram
# REQUIRE: networking
# KEYWORD: 
 
. /etc/rc.subr
 
name="goprogram"
rcvar="goprogram_enable"
command="/usr/local/goprogram/goprogram"
goprogram_user="goprogram"
pidfile="/var/run/${name}.pid"
 
start_cmd="goprogram_start"
stop_cmd="goprogram_stop"
status_cmd="goprogram_status"

goprogram_start() {
        /usr/sbin/daemon -P ${pidfile} -r -f -u $goprogram_user $command
}

goprogram_stop() {
        if [ -e "${pidfile}" ]; then
                kill -s TERM `cat ${pidfile}`
        else
                echo "${name} is not running"
        fi

}

goprogram_status() {
        if [ -e "${pidfile}" ]; then
                echo "${name} is running as pid `cat ${pidfile}`"
        else
                echo "${name} is not running"
        fi
}
 
load_rc_config $name
: ${goprogram_enable:=no}
 
run_rc_command "$1"

Pred použitím scriptu nezabudnite na chmod +x /usr/local/etc/rc.d/goprogram a pridanie goprogram_enable="YES" do /etc/rc.conf.

Test

Poďme vyskúšať náš nový rc.d script. Najskôr spustíme novovytvoreného daemon-a:

service goprogram start

Pri pohľade na bežiace procesy vidíme, že beží supervisor aj supervisovaný program:

ps aux
USER       PID %CPU %MEM   VSZ   RSS TT  STAT STARTED    TIME COMMAND
root      49036  0.0  0.0 10468  1640  -  SsJ  Mon11   0:00.06 daemon: /usr/local/goprogram/goprogram[49037] (daemon)
goprogram 49037  0.0  0.0 41572 12840  -  IJ   Mon11   0:42.54 /usr/local/goprogram/goprogram

Nasimulujme chybu programu a pozrime sa čo sa stane:

kill -9 49037
ps aux
USER       PID %CPU %MEM   VSZ  RSS TT  STAT STARTED    TIME COMMAND
root      49036  0.0  0.0 10468 1644  -  SsJ  Mon11   0:00.07 daemon: /usr/local/goprogram/goprogram[49691] (daemon)
goprogram 49691  0.0  0.0 30940 8788  -  SJ   09:54   0:00.01 /usr/local/goprogram/goprogram

Supervisor detekol, že supervisovaný program s pôvodným pid 49037 skončil a reštarvoval ho. Nová inštancia dostala pid 49691.