27

我有一个要守护的 Perl 脚本。基本上,这个 perl 脚本将每 30 秒读取一次目录,读取它找到的文件,然后处理数据。为简单起见,请考虑以下 Perl 脚本(称为 synpipe_server,在 中有此脚本的符号链接/usr/sbin/):

#!/usr/bin/perl
use strict;
use warnings;

my $continue = 1;
$SIG{'TERM'}  = sub { $continue = 0; print "Caught TERM signal\n"; };
$SIG{'INT'} = sub { $continue = 0; print "Caught INT signal\n"; };

my $i = 0;
while ($continue) {
     #do stuff
     print "Hello, I am running " . ++$i . "\n";
     sleep 3;
}

所以这个脚本基本上每 3 秒打印一次。

然后,因为我想守护这个脚本,我也把这个 bash 脚本(也称为 synpipe_server)放在/etc/init.d/

#!/bin/bash
# synpipe_server : This starts and stops synpipe_server
#
# chkconfig: 12345 12 88
# description: Monitors all production pipelines
# processname: synpipe_server
# pidfile: /var/run/synpipe_server.pid
# Source function library.
. /etc/rc.d/init.d/functions

pname="synpipe_server"
exe="/usr/sbin/synpipe_server"
pidfile="/var/run/${pname}.pid"
lockfile="/var/lock/subsys/${pname}"

[ -x $exe ] || exit 0

RETVAL=0

start() {
    echo -n "Starting $pname : "
    daemon ${exe}
    RETVAL=$?
    PID=$!
    echo
    [ $RETVAL -eq 0 ] && touch ${lockfile}
    echo $PID > ${pidfile}
}

stop() {
    echo -n "Shutting down $pname : "
    killproc ${exe}
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ]; then
        rm -f ${lockfile}
        rm -f ${pidfile}
    fi
}

restart() {
    echo -n "Restarting $pname : "
    stop
    sleep 2
    start
}

case "$1" in
    start)
        start
    ;;
    stop)
        stop
    ;;
    status)
        status ${pname}
    ;;
    restart)
        restart
    ;;
    *)
        echo "Usage: $0 {start|stop|status|restart}"
    ;; esac

exit 0

因此,(如果我很好地理解了守护进程的文档)Perl 脚本应该在后台运行,并且/dev/null如果我执行,输出应该被重定向到:

service synpipe_server start

但这是我得到的:

[root@master init.d]# service synpipe_server start
Starting synpipe_server : Hello, I am running 1
Hello, I am running 2
Hello, I am running 3
Hello, I am running 4
Caught INT signal
                                                           [  OK  ]
[root@master init.d]# 

所以它启动 Perl 脚本,但运行它而不将它从当前终端会话中分离出来,我可以看到我的控制台中打印的输出......这并不是我所期望的。此外,PID 文件是空的(或者只有换行符,daemon 没有返回 pid

有谁知道我做错了什么?

编辑:也许我应该说我在 Red Hat 机器上。

Scientific Linux SL release 5.4 (Boron)

谢谢,托尼

4

4 回答 4

17

我终于在bash init脚本中重新编写了start函数,我不再使用daemon了。

start() {
    echo -n "Starting $pname : "
    #daemon ${exe} # Not working ...
    if [ -s ${pidfile} ]; then
       RETVAL=1
       echo -n "Already running !" && warning
       echo
    else
       nohup ${exe} >/dev/null 2>&1 &
       RETVAL=$?
       PID=$!
       [ $RETVAL -eq 0 ] && touch ${lockfile} && success || failure
       echo
       echo $PID > ${pidfile}
    fi
}

我检查 pid 文件是否不存在(如果存在,只需写一个警告)。如果没有,我使用

 nohup ${exe} >/dev/null 2>&1 &

启动脚本。

我不知道这种方式是否安全(?)但它有效。

于 2011-11-15T08:08:58.113 回答
3

守护进程的正确方法是让它自己与终端分离。这就是大多数大型软件套件的做法,例如apache

不做你所期望的名字背后的理由daemon,以及如何让一个 unix 进程分离到后台,可以1.7 节中找到我如何让我的程序像一个守护进程一样工作?

对于这些长时间运行的程序来说,简单地在后台调用一个程序是不够的。不能正确地将进程从启动它的终端会话中分离出来。此外,启动守护进程的传统方式是手动或从 rc 脚本发出命令。守护进程应该将自己 置于后台。

有关此主题的进一步阅读:nohup 和守护程序有什么区别?

于 2017-02-27T19:07:44.817 回答
0

根据man daemon正确的语法是

daemon [options] -- [command] [command args]

您的 init 脚本启动应该运行类似:

daemon --pidfile ${pidfile} -- ${exe}
于 2011-11-14T17:38:43.690 回答
0

正如这里所说,似乎需要使用&将进程发送到后台。守护进程不为你做。

于 2016-08-18T19:34:39.410 回答