Writing a daemon with PHP

You are currently browsing comments. If you would like to return to the full story, you can read the full entry here: “Writing a daemon with PHP”.

This entry was posted in Programming, Projects and tagged , , , , , , , , . Bookmark the permalink.

19 Responses to Writing a daemon with PHP

  1. Charles says:

    hi, i found this page extremely useful for spawning worker threads. exactly what i needed. however, i don’t quite understand the first line of your script

    #!/usr/bin/php -q

    What’s -q? I’ve looked in man docs and did php -h to see what pop up… I don’t see this switch listed anywhere for PHP. Could you kindly explain?

    Thanks!

    • stuporglue says:

      The PHP man page (for PHP 5.3.3) I have on Ubuntu says this:

      -q Quiet-mode. Suppress HTTP header output (CGI only).

      The -q might not actually be needed for daemons etc. anymore. On an older version of PHP I would get the HTTP headers when I used PHP from the command line, but even without the -q I’m not seeing that anymore. It must see that it’s command-line PHP and not print them.

  2. Jacob says:

    If you daemonize, close your terminal, and then your daemon tries to print, you’re going to have problems. Your daemon will still try to print to STDOUT, which will now be closed. This will likely cause it to fail in an unpleasant manner.
    I start my children via cron or terminal, and have the above problem.
    How can it be fixed?

    • stuporglue says:

      One option is to make sure that your program never prints anything, then you won’t trigger this issue. Another option, for cron at least, is that you can enter your cron command with >/dev/null 2>&1 at the end. >/dev/null redirect stdout to /dev/null of course, and 2>&1 redirects any error output to stdout (which is going to /dev/null).

      Running from a terminal and then closing the terminal may give you one other issue, closing a terminal may send your application SIGHUP which will typically cause a process to exit if it is not handled.

  3. peter says:

    Your code is very useful. However, I want to let the parent process know the exit status of children. e.g. The child exit with an integer like exit(0) or exit(1), etc. Is it possible for the parent to catch that integer? Any other way to let the parent know how child finishes its job?

    Also, in the function: $dead_and_gone = pcntl_waitpid(-1,$status,WNOHANG);
    what is in the variable $status?

    Thanks!

    peter

    • stuporglue says:

      I haven’t needed to get the process exit code for anything yet, but pcntl_waitpid says this:

      pcntl_waitpid() will store status information in the status parameter which can be evaluated using the following functions: pcntl_wifexited(), pcntl_wifstopped(), pcntl_wifsignaled(), pcntl_wexitstatus(), pcntl_wtermsig() and pcntl_wstopsig().

      You can pass $status into pcntl_wexitstatus to get the process code to get the exit code, if pcntl_wifexited returns TRUE.

      The PHP docs will give you more details, examples and caveats http://www.php.net/manual/en/function.pcntl-wifexited.php

  4. Pingback: Adding Pcntl Support to a Shared Host | Stuporglue.org

  5. Pingback: Creating a daemon « Abner’s Postgraduate Days

  6. Brian says:

    Hi Stuporglue,

    Great write up. I have been using php daemons for some time now but this article has given me ideas about something I was scratching my head over. Thanks.

    @Jacob
    Referring to : “If you daemonize, close your terminal, and then your daemon tries to print, you’re going to have problems. Your daemon will still try to print to STDOUT, which will now be closed. This will likely cause it to fail in an unpleasant manner.”

    When you write daemons, you really should not be putting print or echo statements in your code at all. You should write to a log file if you need output using error_log.

    Brian

  7. Trond says:

    Great article. I’ve just looked at your code, but I will certainly test this later.
    When it comes to logging, check this out: http://logging.apache.org/log4php/

    I am using log4net quite a lot in .Net applications, and if the php-version is as good as the log4net, then you have a good logging library to use.

  8. John says:

    Hi Stuporglue,

    I was wondering, in the file “worker.php”, how would I access the arguments I want to pass through from the controller?

    • stuporglue says:

      Hi John,

      Programs launched with pcntl_exec($program,$arguments); are run as command line scripts, so you’ll access the arguments via $argv.

      You can launch non-PHP programs too.

      If your script is PHP you’ll either need to set the shebang to use PHP, or set $program to /usr/bin/php and have the actual script be one of the arguments.

  9. Ron says:

    1. Don’t need “php -q” for PHP CLI.
    2. You really want to fork twice.

    $pid = pcntl_fork();
    if($pid){
    // Only the parent will know the PID. Kids aren't self-aware
    // Parent says goodbye!
    print "\tParent : " . getmypid() . " exiting\n";
    exit();
    }
    // Dissociate from controlling terminal, become session leader
    if (posix_setsid() === -1) {
    die("Error!\n");
    }
    usleep(100000);

    // Fork again as session leader
    $pid = pcntl_fork();

    3. To deal with the “stray I/O”, once you’ve closed the standard file descriptors, open them again, pointed to /dev/null

    fclose(STDIN);
    fclose(STDOUT);
    fclose(STDERR);

    $stdin = fopen('/dev/null', 'r'); // set fd/0
    $stdout = fopen('/dev/null', 'w'); // set fd/1
    $stderr = fopen('php://stdout', 'w'); // hack to duplicate fd/1 to 2

  10. Anastasia says:

    Thanks for such useful article. I have such question: How can I send the data to the daemon. Not signal, but some array of data? In your example, you have empty $arguments array. How will you populate it, in case needed?
    Thanks again!

    • stuporglue says:

      $arguments is in there because pcntl_exec can take an array of arguments for the program which is executed.

      There are several ways you might communicate with the daemon, it all depends what you’re looking for.

      Personally, I have a database set up which accepts job requests from users. The daemon queries the database every time through the while(TRUE) loop to check for more jobs (with a sleep(3) at the end of the while loop so it’s not always running).

      You could also write to a config file (or somewhere else), then have a signal handler and send the daemon a signal to read or re-read those files.

      You could also look into using a named pipe which would let other processes write to the pipe which the daemon could read from on every loop.

      Sockets might also do the job, if that’s what needed.

  11. icecream says:

    Use this will produce a zombie process in linux, It is resonable? It will waste my resources?

    • stuporglue says:

      It shouldn’t create a zombie, but should produce an orphan, which will be adopted by init.

      The child processes which the daemon creates should never become zombies either since we have this loop at the end of our work loop:


      $dead_and_gone = pcntl_waitpid(-1,$status,WNOHANG);
      while($dead_and_gone > 0){
      // Remove the gone pid from the array
      unset($pids[array_search($dead_and_gone,$pids)]);

      // Look for another one
      $dead_and_gone = pcntl_waitpid(-1,$status,WNOHANG);
      }

      I ran a PHP daemon like this for about 18 months for a project I did and didn’t have any problems with zombies.

  12. icecream says:

    PHP use while(true) OR Python use while true:? Which will be better for daemon process?

    • stuporglue says:

      PHP isn’t typically used for daemon processes. I used it because the daemon needed to use the same libraries that our main project was using.

      If I were writing a stand-alone daemon that didn’t need to integrate with the rest of a project, I’d probably use Perl, Python or even Bash if the task were simple enough. Python and Perl both have daemon libraries that will handle the daemonizing process for you.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>