Добрый день. Есть демон. В одной строке должен выполниться exec, и на этом моменте демон убивается сигналом 17. php.net пишет: В самом демоне поток перенаправлен в файл. Но видимо нужно перенаправить от exec. Пробовал разные варианты: PHP: exec('/etc/init.d/crond restart > /dev/null 2>/dev/null &'); и так: PHP: ob_start(); exec('/etc/init.d/crond restart'); ob_end_clean(); Все равно демон убивается. Помогите пожалуйста решить вопрос. Код демона: PHP: <?php // Без этой директивы PHP не будет перехватывать сигналы //sleep(3); declare(ticks=1); ini_set('error_log', '/var/www/html/error.log'); class DaemonClass { public $maxProcesses = 1; // Максимальное количество дочерних процессов protected $stop_server = FALSE; // Когда установится в TRUE, демон завершит работу public $currentJobs = array(); // Здесь будем хранить запущенные дочерние процессы public $start_h = 0; // Время с которого можно начинать рассылку public $end_h = 0; // Время, когда нужно завершить отправку рассылки public function __construct() { error_log('Демон создан'); // Ждем сигналы SIGTERM и SIGCHLD $sig1 = pcntl_signal(SIGTERM, array($this, "childSignalHandler"), true); $sig2 = pcntl_signal(SIGCHLD, array($this, "childSignalHandler"), true); } public function connect(){ if(!defined('MySQL_HOST')) define( 'MySQL_HOST', 'localhost' ); if(!defined('MySQL_LOGIN')) define( 'MySQL_LOGIN', 'xxx' ); if(!defined('MySQL_PASSWORD')) define( 'MySQL_PASSWORD', 'xxx' ); if(!defined('MySQL_DATABASE')) define( 'MySQL_DATABASE', 'xxx' ); $this->conn = mysql_connect(MySQL_HOST, MySQL_LOGIN, MySQL_PASSWORD); mysql_select_db(MySQL_DATABASE); mysql_query("SET NAMES utf8"); } public function query($sql=''){ $return = false; if(!empty($sql)){ if (!mysql_ping($this->conn)){ mysql_close($this->conn); $this->connect(); } $return = mysql_query($sql); } return $return; } protected function allTasks(){ // Тут код какой-то ob_start(); exec('/etc/init.d/crond restart > /dev/null 2>/dev/null &'); ob_end_clean(); } public function launchJob() { error_log("Процесс с ID ".getmypid()); file_put_contents('/var/www/html/pid.pid', getmypid()); chmod('/var/www/html/pid.pid', 0777); $timer_run_1min = 0; while(!$this->stop_server) { //error_log(date('d.m.Y H:i:s')); // Проверка, не спит ли сокет... // Если уже запущено максимальное количество дочерних процессов, ждем их завершения while(count($this->currentJobs) >= $this->maxProcesses) { error_log('Уже дочерних процессов больше допустимого. Отдыхаем секундочку.'); sleep(1); } $curr = time(); // Время в сек. $t_1min = 60; if((int)$timer_run_1min == 0){ $timer_run_1min = $curr; } // Таймер на 1 минуту. if($curr-$timer_run_1min >= $t_1min){ error_log('run ALL TASKS'); $this->allTasks(); $timer_run_1min = $curr; } sleep(1); } exit(); // } return TRUE; } public function childSignalHandler($signo, $pid = null, $status = null) { error_log('Был вызван '.$signo); switch($signo) { case SIGTERM: // При получении сигнала завершения работы устанавливаем флаг $this->stop_server = true; unlink('/var/www/html/pid.pid'); error_log('Стоп циклу. Удаляем PID-файл.'); exit; 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); } unlink('/var/www/html/pid.pid'); error_log('Убиваем все дочерние процессы. Удаляем PID-файл.'); exit; break; default: // все остальные сигналы } pcntl_signal_dispatch(); } } function isDaemonActive($pid_file) { if( is_file($pid_file) ) { $pid = file_get_contents($pid_file); //проверяем на наличие процесса if(posix_kill($pid,0)) { //демон уже запущен return true; } else { //pid-файл есть, но процесса нет if(!unlink($pid_file)) { error_log('не могу уничтожить pid-файл. ошибка'); exit(-1); } error_log('pid-файл умер'); } } return false; } $active = isDaemonActive('/var/www/html/pid.pid'); if ($active) { error_log('Демон уже запущен! Выход.'); exit; }else{ $daemon = new DaemonClass(); $daemon->connect(); $currentJobs = array(); // Создаем дочерний процесс // весь код после pcntl_fork() будет выполняться двумя процессами: родительским и дочерним $child_pid = pcntl_fork(); if ($child_pid == -1) { error_log('Не форкается...'); exit(); } elseif ($child_pid) { $daemon->currentJobs[$child_pid] = TRUE; error_log('Выходим от родителя.'); exit(); }// Выходим из родительского, привязанного к консоли, процесса else{ posix_setsid(); // Делаем основным процессом дочерний. // Дальнейший код выполнится только дочерним процессом, который уже отвязан от консоли error_log('Дочерний процесс самый главный!'); fclose(STDIN); fclose(STDOUT); fclose(STDERR); $STDIN = fopen('/dev/null', 'r'); $STDOUT = fopen('/var/www/html/application.log', 'ab'); $STDERR = fopen('/var/www/html/daemon.log', 'ab'); //if(count($currentJobs) > 0){ $daemon->currentJobs = $currentJobs; error_log('Пишем PID в класс'); } $daemon->launchJob(); } } ?>
В теории по идее это оно и есть. Но оно почему-то не работает. PS. Временно отключил обработку сигналов, оставил только SIGTERM. Но это не красиво. Хотелось бы все-таки найти в чем подвох и как его решить.