📜 ⬆️ ⬇️

PHP demons

Memo to a novice exorcist.

Before I start: I know what phpDaemon and System_Daemon are. I read articles on this topic, and on Habré too.

So, suppose that you have already decided that you need a demon. What should he be able to?

Unbound from the console


//    //    pcntl_fork()    :    $child_pid = pcntl_fork(); if ($child_pid) { //   ,   ,  exit(); } //    . posix_setsid(); //      ,      


The pcntl_fork () function creates a child process and returns its id. However, the $ child_pid variable does not fall into the child process (more precisely, it will be equal to 0), respectively, only the parent process will pass the test. It will end, and the child process will continue executing the code.
')
In general, we have already created the demon, but it will still output all information (including errors) to the console. Yes, and completed immediately after execution.

Override output


 $baseDir = dirname(__FILE__); ini_set('error_log',$baseDir.'/error.log'); fclose(STDIN); fclose(STDOUT); fclose(STDERR); $STDIN = fopen('/dev/null', 'r'); $STDOUT = fopen($baseDir.'/application.log', 'ab'); $STDERR = fopen($baseDir.'/daemon.log', 'ab'); 

Here we close the standard output streams and send them to a file. STDIN just in case open for reading from / dev / null, since our demon will not read from the console - it is untied from it. Now the entire output of our daemon will be logged in files.

Go!


 include 'DaemonClass.php'; $daemon = new DaemonClass(); $daemon->run(); 

Once we have redefined the output, you can perform the task set by the daemon. Let's create DaemonClass.php and start writing a class that will do the main work of our demon.

DaemonClass.php


 //    PHP     declare(ticks=1); class DaemonClass { //     public $maxProcesses = 5; //    TRUE,    protected $stop_server = FALSE; //       protected $currentJobs = array(); public function __construct() { echo "onstructed daemon controller".PHP_EOL; //   SIGTERM  SIGCHLD pcntl_signal(SIGTERM, array($this, "childSignalHandler")); pcntl_signal(SIGCHLD, array($this, "childSignalHandler")); } public function run() { echo "Running daemon controller".PHP_EOL; //  $stop_server    TRUE,    while (!$this->stop_server) { //       ,    while(count($this->currentJobs) >= $this->maxProcesses) { echo "Maximum children allowed, waiting...".PHP_EOL; sleep(1); } $this->launchJob(); } } } 

We expect signals SIGTERM (completion of work) and SIGCHLD (from child processes). Run an infinite loop so that the daemon does not end. We check whether it is possible to create another child process and wait if it is impossible.

  protected function launchJob() { //    //    pcntl_fork()   //  :    $pid = pcntl_fork(); if ($pid == -1) { //      error_log('Could not launch new job, exiting'); return FALSE; } elseif ($pid) { //      $this->currentJobs[$pid] = TRUE; } else { //       echo "  ID ".getmypid().PHP_EOL; exit(); } return TRUE; } 

pcntl_fork () returns -1 in case of an error, $ pid will be available in the parent process, in the child of this variable will not be (more precisely, it will be equal to 0).

  public function childSignalHandler($signo, $pid = null, $status = null) { switch($signo) { case SIGTERM: //        $this->stop_server = true; break; case SIGCHLD: //       if (!$pid) { $pid = pcntl_waitpid(-1, $status, WNOHANG); } //      while ($pid > 0) { if ($pid && isset($this->currentJobs[$pid])) { //      unset($this->currentJobs[$pid]); } $pid = pcntl_waitpid(-1, $status, WNOHANG); } break; default: //    } } 

SIGTERM is the correct completion signal. SIGCHLD is a signal to terminate the work of a child process. When the child process terminates, we remove it from the list of running processes. Upon receipt of SIGTERM, set a flag - our “infinite loop” will end when the current task is completed.

It remains to prohibit the launch of several copies of the daemon, this is perfectly written in this article .

Thanks for attention.

UPD: Habrayuzer Dlussky in his comments suggested that in PHP> = 5.3.0, instead of declare (ticks = 1), use pcntl_signal_dispatch ()

Source: https://habr.com/ru/post/134620/


All Articles