Search code examples
phplinuxdaemon

Daemonizing php script on Centos


Running into some problems trying to daemonize a php script on Centos Linux environment. It's unfortunate that Centos only has the limited daemon function and not the start-stop-daemon...

I'm trying to create a service that runs a php script continuously until a signal is caught. I also would like a php script to start the service as well.

  • foolauncher.php launches the service via system('service foo start')
  • /etc/init.d/foo starts foo.php
  • foo.php spawns the child process to daemonize and parent exits

However, when i start foolauncher.php, it shows the init.d script starting my foo.php service, doesn't release the terminal, but instead outputs my system call. When I send a SIGINT to quit the parent, the foo service stops running as well.

I know the location of the problem is in foo.php:

$output = system('service foo status');

If I omit that line for the system call, sending a SIGINT to quit the parent will not affect the foo service.

I'm aware of fclose(STDERR), fclose(STDOUT), and fclose(STDIN), but I'm not sure where I would actually close these outputs, as it seems to cause similar issues as sending a SIGINT to the parent; foo.php still similarly dies on the system call.

It seems as if because I am outputting something to STDOUT, the parent can't fully release the child... I'm not looking to use other methods of deamonizing (ie. System Daemon, nohup), or using a cron job to execute (even though I have heard that daemonizing php is not a good idea), but a solution to how this problem can be solved.

Any recommendations, advice, or solutions would be much, much appreciated! Thanks!

Here are the files:

foolauncher.php:

<?php
system('service foo start');

foo.php:

<?php

declare(ticks = 1);
$pid = pcntl_fork();

if ($pid < 0)
{
    system("echo 'failed to fork' >> /foo/foo.log");
    exit;
}
else if ($pid)
{
    system("echo 'parent exiting' >> /foo/foo.log");
    exit;
}
$sid = posix_setsid();
if ($sid < 0)
{
    exit;
}

pcntl_signal(SIGTERM, "signalHandler");
pcntl_signal(SIGINT, "signalHandler");

$daemonPid = posix_getpid();
system("echo 'Process started on $daemonPid!\n' >> /foo/foo.log");
system("echo $daemonPid > /var/run/foo.pid");

while(true)
{
    // If I dont have this line, everything daemonizes nicely
    $output = system("service foo status");
    system("echo 'In infinite loop still! $output\n' >> /foo/foo.log");
    sleep(3);
}

function signalHandler($signo)
{

    switch($signo)
    {
        case SIGTERM:
        {
            system("echo 'SIGTERM caught!\n' >> /foo/foo.log");
            exit();
        }
        case SIGINT:
        {
            system("echo 'SIGINT caught!\n' >> /foo/foo.log");
            exit();
        }
    }
}

/etc/init.d/foo

# Source function library.
. /etc/rc.d/init.d/functions

php=${PHP-/usr/bin/php}
foo=${FOO-/foo/foo.php}
prog=`/bin/basename $foo`
lockfile=${LOCKFILE-/var/lock/subsys/foo}
pidfile=${PIDFILE-/var/run/foo.pid}
RETVAL=0

start() {
    echo -n $"Starting $prog: "

    daemon --pidfile=${pidfile} ${php} ${foo}
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && touch ${lockfile}
    return $RETVAL
}

stop() {
    echo -n $"Stopping $prog: "
    killproc -p ${pidfile} ${prog}
    RETVAL=$?
    echo
    [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}


rh_status() {
    status -p ${pidfile} ${foo}
}

# See how we were called.
case "$1" in
    start)
        rh_status >/dev/null 2>&1 && exit 0
        start
        ;;
    stop)
        stop
        ;;
    status)
        rh_status
        RETVAL=$?
        ;;
    restart)
        configtest -q || exit $RETVAL
        stop
        start
        ;;
    *)
        echo $"Usage: $prog {start|stop|restart|status}"
        RETVAL=2
esac
exit $RETVAL

Solution

  • Found a solution!

    I was able to get the service to daemonize nicely simply by redirecting stdout and stderr to /dev/null

    From foolauncher.php

    <?php
    system('service foo start &> /dev/null');
    

    Seems to do what I want it to!