* @package PHPCI * @subpackage Console */ class DaemonCommand extends Command { /** * @var Logger */ protected $logger; /** * @var string */ protected $pidFilePath; /** * @var string */ protected $logFilePath; /** * @var ProcessControlInterface */ protected $processControl; public function __construct(Logger $logger, ProcessControlInterface $processControl = null, $name = null) { parent::__construct($name); $this->logger = $logger; $this->processControl = $processControl ?: Factory::getInstance(); } protected function configure() { $this ->setName('php-censor:daemon') ->setDescription('Initiates the daemon to run commands.') ->addArgument( 'state', InputArgument::REQUIRED, 'start|stop|status' )->addOption( 'pid-file', 'p', InputOption::VALUE_REQUIRED, 'Path of the PID file', (ROOT_DIR . 'runtime' . DIRECTORY_SEPARATOR . 'daemon' . DIRECTORY_SEPARATOR . 'daemon.pid') )->addOption( 'log-file', 'l', InputOption::VALUE_REQUIRED, 'Path of the log file', (ROOT_DIR . 'runtime' . DIRECTORY_SEPARATOR . 'daemon' . DIRECTORY_SEPARATOR . 'daemon.log') ); } /** * Loops through running. */ protected function execute(InputInterface $input, OutputInterface $output) { $this->pidFilePath = $input->getOption('pid-file'); $this->logFilePath = $input->getOption('log-file'); $state = $input->getArgument('state'); switch ($state) { case 'start': $this->startDaemon(); break; case 'stop': $this->stopDaemon(); break; case 'status': $this->statusDaemon($output); break; default: $this->output->writeln("Not a valid choice, please use start, stop or status"); break; } } protected function startDaemon() { $pid = $this->getRunningPid(); if ($pid) { $this->logger->notice("Daemon already started", ['pid' => $pid]); return "alreadystarted"; } $this->logger->info("Trying to start the daemon"); $cmd = "nohup %sdaemonise php-censor:daemonise > %s 2>&1 &"; $command = sprintf($cmd, BIN_DIR, $this->logFilePath); $output = $exitCode = null; exec($command, $output, $exitCode); if ($exitCode !== 0) { $this->logger->error(sprintf("daemonise exited with status %d", $exitCode)); return "notstarted"; } for ($i = 0; !($pid = $this->getRunningPid()) && $i < 5; $i++) { sleep(1); } if (!$pid) { $this->logger->error("Could not start the daemon"); return "notstarted"; } $this->logger->notice("Daemon started", ['pid' => $pid]); return "started"; } protected function stopDaemon() { $pid = $this->getRunningPid(); if (!$pid) { $this->logger->notice("Cannot stop the daemon as it is not started"); return "notstarted"; } $this->logger->info("Trying to terminate the daemon", ['pid' => $pid]); $this->processControl->kill($pid); for ($i = 0; ($pid = $this->getRunningPid()) && $i < 5; $i++) { sleep(1); } if ($pid) { $this->logger->warning("The daemon is resiting, trying to kill it", ['pid' => $pid]); $this->processControl->kill($pid, true); for ($i = 0; ($pid = $this->getRunningPid()) && $i < 5; $i++) { sleep(1); } } if (!$pid) { $this->logger->notice("Daemon stopped"); return "stopped"; } $this->logger->error("Could not stop the daemon"); } protected function statusDaemon(OutputInterface $output) { $pid = $this->getRunningPid(); if ($pid) { $output->writeln(sprintf('The daemon is running, PID: %d', $pid)); return "running"; } $output->writeln('The daemon is not running'); return "notrunning"; } /** Check if there is a running daemon * * @return int|null */ protected function getRunningPid() { if (!file_exists($this->pidFilePath)) { return; } $pid = intval(trim(file_get_contents($this->pidFilePath))); if($this->processControl->isRunning($pid)) { return $pid; } // Not found, remove the stale PID file unlink($this->pidFilePath); } }