/**
  * Запуск сервиса.
  * 
  * @access protected
  * @static
  */
 protected static function cmdStart()
 {
     echo "Starting Pinger service... ";
     try {
         // проверка PID-файла
         Assets\PID::PreLock();
         $ruid = posix_getpwnam(Assets\Config::$exec_user)['uid'];
         $rgid = posix_getgrnam(Assets\Config::$exec_group)['gid'];
         if (null === $ruid || null === $rgid) {
             printf(" [FAIL]\nRequired exec user:group [%s:%s] was not found.\n", Assets\Config::$exec_user, Assets\Config::$exec_group);
             exit(1);
         }
         // попытка запуска Мастер-процесса
         $pid = @pcntl_fork();
         if ($pid == -1) {
             // ошибка ветвления
             throw new Assets\Exceptions\Master_Fork_Fail_Exception();
         } elseif ($pid) {
             //
             // рутины родительского процесса - сценария SBINDIR/pinger
             //
             printf(" [OK]\nLooks like Master forked with PID=%d\n", $pid);
             exit(0);
         } else {
             //
             // рутины дочернего процесса - Мастер-процесса
             //
             // переключение группы-владельца процесса
             // выполняется ДО переключения пользователя-владельца
             if (!posix_setegid($rgid)) {
                 printf("Failed to posix_setegid(%d) [%s].\n", $rgid, Assets\Config::$exec_group);
                 exit(1);
             }
             // переключение пользователя-владельца процесса
             if (!posix_seteuid($ruid)) {
                 printf("Failed to posix_seteuid(%d) [%s].\n", $ruid, Assets\Config::$exec_user);
                 exit(1);
             }
             // открытие журналов
             TwinLog::init(PINGER_LOGDIR, 'Master');
             // закрытие дескрипторов
             @fclose(STDIN);
             @fclose(STDOUT);
             @fclose(STDERR);
             // вход в Мастер-процесс
             Daemon\Master::main();
             // закрытие журналов
             TwinLog::kill();
             // успешный выход
             // exit(0) не используется для возможности перезапуска
             // с применением этого метода
         }
     } catch (Assets\Exceptions\PID_Open_Fail_Exception $e) {
         echo " [FAIL]\n PID-file exists but unreadable\n";
         exit(1);
     } catch (Assets\Exceptions\PID_Lock_Fail_Exception $e) {
         printf("\n Daemon already running with PID=%d", Assets\PID::$pid);
         exit(1);
     } catch (Assets\Exceptions\PID_Read_Fail_Exception $e) {
         echo " [FAIL]\n PID-file exists and locked\n";
         echo " PID-file reading failed!\n";
         exit(1);
     } catch (Assets\Exceptions\PID_Unlink_Fail_Exception $e) {
         echo " [FAIL]\n PID-file exists but failed to unlink\n";
         exit(1);
     } catch (Assets\Exceptions\Master_Fork_Fail_Exception $e) {
         echo " [FAIL]\n fork() failed\n";
         exit(1);
     } catch (\Exception $e) {
         echo " [FAIL]\n Unexpected exception:\n";
         var_export($e->getMessage());
         var_export($e->getTraceAsString());
         exit(1);
     }
 }
Exemple #2
0
 /**
  * Запуск Воркеров выбранного типа.
  * 
  * @param string $type
  * @throws \Ganzal\Lulz\Pinger\Assets\Exceptions\Worker_Fork_Fail_Exception
  */
 protected static function launchWorkers($type)
 {
     DEBUG && printf("Master::launchWorkers(%s)/master: begin\n", $type);
     // обновление слотов Воркеров
     static::recalcSlots();
     // полное квалифицированное имя запускаемого метода Воркера
     $forkCallback = __NAMESPACE__ . '\\' . $type . 'Worker::main';
     DEBUG && printf("Master::launchWorkers()/master: forkCallback = %s\n", $forkCallback);
     // запуск Воркеров во все доступные слоты
     while ($slot = array_shift(static::$pid_slots)) {
         ++static::$fork_num;
         DEBUG && printf("Master::launchWorkers()/master: slot #%d for fork #%d\n", $slot, static::$fork_num);
         // попытка запуска дочернего процесса
         $pid = @pcntl_fork();
         if ($pid == -1) {
             // ошибка ветвления
             throw new Exceptions\Worker_Fork_Fail_Exception();
         } elseif ($pid) {
             //
             // рутины родительского процесса
             //
             DEBUG && printf("Master::launchWorkers()/master: forked with PID %d to slot #%d\n", $pid, $slot);
             // регистрация дочернего процесса в списоке активных заданий
             static::$jobs[$pid] = $slot;
             DEBUG && printf("Master::launchWorkers()/master: jobs\n%s\n", var_export(static::$jobs, true));
             // продолжаем цикл Мастера
             DEBUG && (print "Master::launchWorkers()/master: fill next slot\n");
             continue;
         }
         //
         // рутины дочернего процесса
         //
         cli_set_process_title('PingerService/' . $type . 'Worker');
         DEBUG && printf("Master::launchWorkers()/worker/%d: begin\n", static::$fork_num);
         // закрытие стандартных дескрипторов на случай, если
         // Мастер запускался напрямую, а не через SBINDIR/pinger.
         if ('resource' == gettype(STDIN)) {
             DEBUG && printf("Master::launchWorkers()/worker/%d: @fclose(STDIN);\n", static::$fork_num);
             @fclose(STDIN);
         }
         if ('resource' == gettype(STDOUT)) {
             DEBUG && printf("Master::launchWorkers()/worker/%d: @fclose(STDOUT);\n", static::$fork_num);
             @fclose(STDOUT);
         }
         if ('resource' == gettype(STDERR)) {
             DEBUG && printf("Master::launchWorkers()/worker/%d: @fclose(STDERR);\n", static::$fork_num);
             @fclose(STDERR);
         }
         // перемещение журнала
         DEBUG && printf("Master::launchWorkers()/worker/%d: TwinLog::rename(PINGER_LOGFILE, '%sWorker', %d)\n", static::$fork_num, $type, $slot);
         TwinLog::rename(PINGER_LOGDIR, $type . 'Worker', $slot);
         call_user_func($forkCallback);
         DEBUG && printf("Master::launchWorkers()/worker/%d: end\n\n", static::$fork_num);
         TwinLog::kill(true);
         // хорошо завершились
         exit(0);
     }
     // while (static::$master_loop)
     DEBUG && (print "Master::launchWorkers()/master: end\n\n");
 }