Reworked the DaemonCommand.

* Accepts options for PID and log file.
* Uses posix_kill whenever available.
* Checks that the daemon actually started or stopped.
* Try to terminate then kill the daemon.
* Uses the logger or output instead of "echo".
This commit is contained in:
Adirelle 2015-04-09 08:51:45 +02:00 committed by Adirelle
parent 8bf1d09afd
commit b87dac145d

View file

@ -1,4 +1,5 @@
<?php
/**
* PHPCI - Continuous Integration for PHP
*
@ -13,21 +14,33 @@ use Monolog\Logger;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Daemon that loops and call the run-command.
* @author Gabriel Baker <gabriel.baker@autonomicpilot.co.uk>
* @package PHPCI
* @subpackage Console
*/
* Daemon that loops and call the run-command.
* @author Gabriel Baker <gabriel.baker@autonomicpilot.co.uk>
* @package PHPCI
* @subpackage Console
*/
class DaemonCommand extends Command
{
/**
* @var \Monolog\Logger
* @var Logger
*/
protected $logger;
/**
* @var string
*/
protected $pidFilePath;
/**
* @var string
*/
protected $logFilePath;
public function __construct(Logger $logger, $name = null)
{
parent::__construct($name);
@ -40,17 +53,30 @@ class DaemonCommand extends Command
->setName('phpci:daemon')
->setDescription('Initiates the daemon to run commands.')
->addArgument(
'state',
InputArgument::REQUIRED,
'start|stop|status'
);
'state', InputArgument::REQUIRED, 'start|stop|status'
)
->addOption(
'pid-file', 'p', InputOption::VALUE_REQUIRED,
'Path of the PID file',
implode(DIRECTORY_SEPARATOR,
array(PHPCI_DIR, 'daemon', 'daemon.pid'))
)
->addOption(
'log-file', 'l', InputOption::VALUE_REQUIRED,
'Path of the log file',
implode(DIRECTORY_SEPARATOR,
array(PHPCI_DIR, 'daemon', 'daemon.log'))
);
}
/**
* Loops through running.
*/
* 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) {
@ -61,64 +87,139 @@ class DaemonCommand extends Command
$this->stopDaemon();
break;
case 'status':
$this->statusDaemon();
$this->statusDaemon($output);
break;
default:
echo "Not a valid choice, please use start stop or status";
$this->output->writeln("<error>Not a valid choice, please use start, stop or status</error>");
break;
}
}
protected function startDaemon()
{
if (file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
echo "Already started\n";
$this->logger->warning("Daemon already started");
$pid = $this->getRunningPid();
if ($pid) {
$this->logger->notice("Daemon already started", array('pid' => $pid));
return "alreadystarted";
}
$logfile = PHPCI_DIR."/daemon/daemon.log";
$this->logger->info("Trying to start the daemon");
$cmd = "nohup %s/daemonise phpci:daemonise > %s 2>&1 &";
$command = sprintf($cmd, PHPCI_DIR, $logfile);
$this->logger->info("Daemon started");
exec($command);
$command = sprintf($cmd, PHPCI_DIR, $this->logFilePath);
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", array('pid' => $pid));
return "started";
}
protected function stopDaemon()
{
if (!file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
echo "Not started\n";
$this->logger->warning("Can't stop daemon as not started");
$pid = $this->getRunningPid();
if (!$pid) {
$this->logger->notice("Cannot stop the daemon as it is not started");
return "notstarted";
}
$cmd = "kill $(cat %s/daemon/daemon.pid)";
$command = sprintf($cmd, PHPCI_DIR);
exec($command);
$this->logger->info("Daemon stopped");
unlink(PHPCI_DIR.'/daemon/daemon.pid');
}
$this->logger->info("Trying to terminate the daemon", array('pid' => $pid));
$this->kill($pid, 15);
protected function statusDaemon()
{
if (!file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
echo "Not running\n";
return "notrunning";
for ($i = 0; ($pid = $this->getRunningPid()) && $i < 5; $i++) {
sleep(1);
}
$pid = trim(file_get_contents(PHPCI_DIR.'/daemon/daemon.pid'));
$pidcheck = sprintf("/proc/%s", $pid);
if (is_dir($pidcheck)) {
echo "Running\n";
if ($pid) {
$this->logger->warning("The daemon is resiting, trying to kill it", array('pid' => $pid));
$this->kill($pid, 9);
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";
}
unlink(PHPCI_DIR.'/daemon/daemon.pid');
echo "Not running\n";
$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 (function_exists('posix_kill')) {
// Use posix_kill with signal 0
if (@posix_kill($pid, 0)) {
// Signal 0 isn't sent but posix_kill checks the process anyway
return $pid;
}
} elseif (is_dir('/proc')) {
// Use linux's /proc filesystem
if (is_dir('/proc/' . $pid)) {
return $pid;
}
} else {
// Last resort: the ps command
exec(sprintf('ps %d', $pid), $output, $exitCode);
if ($exitCode === 0) {
return $pid;
}
}
// Not found, remove the stale PID file
unlink($this->pidFilePath);
}
/** Kill a process
*
* @param int $pid
* @param int $signal
*/
protected function kill($pid, $signal = 15)
{
if (function_exists('posix_kill')) {
return posix_kill($pid, $signal);
}
exec(sprintf('kill -%d %d', $signal, $pid), null, $exitCode);
return $exitCode === 0;
}
}