在 Debian 中将 PHP 脚本作为守护进程运行


Running a PHP Script as a Daemon in Debian

我正在尝试在 Debian 中启动一个 php 脚本作为守护进程。我也希望它也从启动开始。

我一直在毫无问题地开始使用/path/to/php /path/to/script/Insert.php &,也可以shell_exec("nohup /path/to/php /path/to/script/Insert.php >/dev/null &")。我尝试使用以下脚本,但它不会使脚本进入运行状态。

正在将文件复制到/etc/init.d/并使用update-rc.d没有问题。我可以使用service congen-insert start来"启动"脚本,但它似乎并没有真正运行,也没有开始做任何工作。

我错过了什么,或者脚本哪里出了问题?

我知道有几种方法可以解决这个问题,但我真的只是想了解我做错了什么,或者为什么我正在做的事情不起作用。

任何帮助或建议都非常感谢!如果您还有其他需要或我在描述中遗漏的任何内容,请告诉我,以便我更正。

提前谢谢。

服务脚本

#! /bin/sh
### BEGIN INIT INFO
# Provides:          congen-insert
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: congen-insert
# Description:       DB Insert Daemon
### END INIT INFO
NAME="congen-insert"
DESC=" DB Insert Daemon"
PIDFILE="/var/run/${NAME}.pid"
LOGFILE="/var/log/${NAME}.log"
DAEMON="/path/to/php"
DAEMON_OPTS="/path/to/script/Insert.php"
START_OPTS="--start --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} ${DAEMON_OPTS}"
STOP_OPTS="--stop --pidfile ${PIDFILE}"
test -x $DAEMON || exit 0
set -e
case "$1" in
    start)
        echo -n "Starting ${DESC}: "
        start-stop-daemon $START_OPTS >> $LOGFILE
        echo "$NAME."
        ;;
    stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon $STOP_OPTS
        echo "$NAME."
        rm -f $PIDFILE
        ;;
    restart|force-reload)
        echo -n "Restarting $DESC: "
        start-stop-daemon $STOP_OPTS
        sleep 1
        start-stop-daemon $START_OPTS >> $LOGFILE
        echo "$NAME."
        ;;
    status)
    echo -n "Sorry, this isn't implemented yet"
    ;;
    *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload}" >&2
        exit 1
        ;;
esac
exit 0

我正在尝试运行的脚本:

const LoaderPath = __DIR__ . DIRECTORY_SEPARATOR . ".." .DIRECTORY_SEPARATOR . "includes.php";
require_once  LoaderPath;
use PhpAmqpLib'Channel'AMQPChannel;
use PhpAmqpLib'Message'AMQPMessage;
use requests'InsertRequest;
$connection = GetRabbitConnection();
$channel = $connection->channel();
$RedisClient = GetRedisClient();
DeclareQueues($connection, $RedisClient);
$MySQLHost = $RedisClient->get(MySQLHostKey);
$MySQLUser = $RedisClient->get(MySQLUserKey);
$MySQLPassword = $RedisClient->get(MySQLPasswordKey);
$MySQLDatabase = $RedisClient->get(MySQLDatabaseKey);
$InsertExchange = $RedisClient->get(Insert.":".Exchange);
$InsertQueue = $RedisClient->get(Insert.":".Queue);
$Prefetch = $RedisClient->get(Insert.":".Prefetch);
$RedisClient->disconnect();
$RedisClient = null;
$mysql= new mysqli($MySQLHost, $MySQLUser, $MySQLPassword, $MySQLDatabase);
$channel->basic_qos(0,$Prefetch,false);
$channel->basic_consume($InsertQueue, $InsertExchange, false, false, false, false, "callback");

echo "Consuming on Exchange $InsertExchange with Queue $InsertQueue'n";
while(true) {
    $channel->wait();
}
$channel->close();
function callback(AMQPMessage $message){
    global $mysql;
    echo "Message received", "'n";
    $InsertRequest = new InsertRequest($message->body);
    echo "Running Insert Statement'n";
    if (!$mysql->query($InsertRequest->SQL)){
        echo "Error: ".$mysql->error;
    }
    /** @type AMQPChannel $channel */
    $channel = $message->delivery_info['channel'];
    $channel->basic_ack($message->delivery_info['delivery_tag']);
    echo "Insert Complete'n";
}

问题出在输出的重定向中。我还用 bash 的标题修改了 php 文件,这样它就不会在顶部显示为多个 php 进程,而是显示文件名:

修订的服务脚本:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          congen-insert
# Required-Start:    $local_fs $network
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: congen-insert
# Description:       ConGen DB Insert Daemon
### END INIT INFO
NAME="congen-insert"
DESC="DB Insert Process for ConGen"
PIDFILE="/var/run/${NAME}.pid"
LOGFILE="/var/log/${NAME}.log"
DAEMON="/var/congen/php/controllers/congen-insert"
DAEMON_OPTS="> /dev/null 2>&1"
START_OPTS="--start --background --make-pidfile --pidfile ${PIDFILE} --exec ${DAEMON} ${DAEMON_OPTS}"
STOP_OPTS="--stop --pidfile ${PIDFILE}"
test -x $DAEMON || exit 0
set -e
case "$1" in
    start)
        echo -n "Starting ${DESC}: "
        start-stop-daemon $START_OPTS >> $LOGFILE
        echo "$NAME."
        ;;
    stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon $STOP_OPTS
        echo "$NAME."
        rm -f $PIDFILE
        ;;
    restart|force-reload)
        echo -n "Restarting $DESC: "
        start-stop-daemon $STOP_OPTS
        sleep 1
        start-stop-daemon $START_OPTS >> $LOGFILE
        echo "$NAME."
        ;;
    status)
    echo -n "Sorry, this isn't implemented yet"
    ;;
    *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload}" >&2
        exit 1
        ;;
esac
exit 0

修改了 PHP 脚本以运行:

#!/php52/php-5.6.6/bin/php
<?php
    const LoaderPath = __DIR__ . DIRECTORY_SEPARATOR . ".." . DIRECTORY_SEPARATOR . "includes.php";
    require_once  LoaderPath;
    use PhpAmqpLib'Channel'AMQPChannel;
    use PhpAmqpLib'Message'AMQPMessage;
    use requests'InsertRequest;
    $connection = GetRabbitConnection();
    $channel = $connection->channel();
    $RedisClient = GetRedisClient();
    DeclareQueues($connection, $RedisClient);
    $InsertExchange = $RedisClient->get(Insert.":".Exchange);
    $InsertQueue = $RedisClient->get(Insert.":".Queue);
    $Prefetch = $RedisClient->get(Insert.":".Prefetch);
    $RedisClient->disconnect();
    $RedisClient = null;
    $mysql= ConnectionBuilder::GetMySQLi();
    $channel->basic_qos(0,$Prefetch,false);
    $channel->basic_consume($InsertQueue, $InsertExchange, false, false, false, false, "callback");

    echo "Consuming on Exchange $InsertExchange with Queue $InsertQueue'n";
    while(true) {
        $channel->wait();
    }
    $channel->close();
    function callback(AMQPMessage $message){
        global $mysql;
        echo "Message received", "'n";
        $InsertRequest = new InsertRequest($message->body);
        echo "Running Insert Statement'n";
        if (!$mysql->query($InsertRequest->SQL)){
            echo "Error: ".$mysql->error;
        }
        /** @type AMQPChannel $channel */
        $channel = $message->delivery_info['channel'];
        $channel->basic_ack($message->delivery_info['delivery_tag']);
        echo "Insert Complete'n";
    }

将文件添加到/etc/init.d/并使 php 脚本和服务脚本都可执行后,我可以使用 service congen-insert start 启动服务,并像使用任何其他 init.d 服务一样使用其余命令。

应该注意的是,我正在将控制台重定向到/dev/null,但您也可以通过将/dev/null替换为可写路径来重定向到文件。

从另一篇SO帖子中引用的2>&1解释" 2是stderr(错误消息(的流号,1表示[原文如此]stdout流(标准非错误输出流(",因此,我实际上是将stdout重定向到/dev/null并将stderr重定向到stdout

  1. 使用交互式 shell 命令编写脚本来执行 php 脚本,如终端 php 示例所示。这仅在编译 PHP 以包含 --with-readline 选项时才有效

  2. 设置 cron 任务
  3. (linux 任务调度程序(以运行此脚本,如 cron 设置示例中所示。