src/Hodor/Daemon/SupervisordManager.php
<?php
namespace Hodor\Daemon;
use Exception;
use Hodor\JobQueue\Config;
class SupervisordManager implements ManagerInterface
{
/**
* @var Config
*/
private $config;
/**
* @param Config $config
*/
public function __construct(Config $config)
{
$this->config = $config;
}
/**
* @throws Exception
*/
public function setupDaemon()
{
$raw_daemon_config = $this->getRawDaemonConfig();
$config_path = $raw_daemon_config['config_path'];
$config_contents = '';
foreach ($this->getDaemonConfig() as $program) {
$config_contents .= $this->generateProgramText($program) . "\n";
}
if (!is_writable(dirname($config_path))
|| (file_exists($config_path) && !is_writable($config_path))
|| false === file_put_contents($config_path, $config_contents)
) {
throw new Exception("Could not write to config file '{$config_path}'.\n");
}
}
/**
* @return array
*/
public function getDaemonConfig()
{
$queue_configs = $this->config->getWorkerConfig()->getWorkerConfigs();
$raw_daemon_config = $this->getRawDaemonConfig();
$programs = [];
foreach ($queue_configs as $queue_config) {
$program_config = array_replace_recursive(
$raw_daemon_config,
$queue_config
);
$this->evaluateProgramName($program_config);
$program_config['command'] = $this->generateCommandString($program_config);
$programs[$program_config['program_name']] = $this->getProgram($program_config);
}
return $programs;
}
/**
* @param array $program_config
* @return string
*/
private function generateCommandString(array $program_config)
{
$program_config['program_prefix'] = '';
$command_pieces = [
'/usr/bin/env php',
escapeshellarg($program_config['command']),
'-c ' . escapeshellarg($this->config->getConfigPath()),
];
if ('superqueuer' !== $program_config['worker_type']) {
$command_pieces[] = '-q ' . escapeshellarg($program_config['worker_name']);
}
return implode(" ", $command_pieces);
}
/**
* @param array & $program_config
* @return void
*/
private function evaluateProgramName(array & $program_config)
{
$search = [
'{{PROGRAM_PREFIX}}',
'{{WORKER_TYPE}}',
'{{WORKER_NAME}}',
];
$replace = [
$program_config['program_prefix'],
$program_config['worker_type'],
$program_config['worker_name'],
];
$program_config['program_name'] = str_replace(
$search,
$replace,
$program_config['program_name']
);
}
/**
* @return array
*/
private function getRawDaemonConfig()
{
$defaults = [
'config_path' => '/etc/supervisord/conf.d/hodor.conf',
'process_owner' => 'apache',
'program_prefix' => 'hodor',
'program_name' => '{{PROGRAM_PREFIX}}-{{WORKER_TYPE}}-{{WORKER_NAME}}',
'logs' => [
'error' => [
'path' => '/var/log/hodor/%(program_name)s_%(process_num)d.error.log',
'max_size' => '10MB',
'rotate_count' => 2,
],
'debug' => [
'path' => '/var/log/hodor/%(program_name)s_%(process_num)d.debug.log',
'max_size' => '10MB',
'rotate_count' => 2,
],
],
];
return array_replace_recursive(
$defaults,
$this->config->getDaemonConfig()
);
}
/**
* @param array $queue_program_config
* @return array
*/
private function getProgram(array $queue_program_config)
{
return [
'program_name' => $queue_program_config['program_name'],
'command' => $queue_program_config['command'],
'process_name' => '%(program_name)s_%(process_num)d',
'numprocs' => $queue_program_config['process_count'],
'numprocs_start' => 0,
'autorestart' => 'true',
'autostart' => 'true',
'startsecs' => 0,
'startretries' => 3,
'user' => $queue_program_config['process_owner'],
'stopsignal' => 'TERM',
'stderr_logfile' => $queue_program_config['logs']['error']['path'],
'stderr_logfile_maxbytes' => $queue_program_config['logs']['error']['max_size'],
'stderr_logfile_backups' => $queue_program_config['logs']['error']['rotate_count'],
'stdout_logfile' => $queue_program_config['logs']['debug']['path'],
'stdout_logfile_maxbytes' => $queue_program_config['logs']['debug']['max_size'],
'stdout_logfile_backups' => $queue_program_config['logs']['debug']['rotate_count'],
];
}
/**
* @param array $program
* @return string
*/
private function generateProgramText(array $program)
{
$text = "[program:{$program['program_name']}]\n";
unset($program['program_name']);
foreach ($program as $key => $value) {
$text .= "{$key}={$value}\n";
}
return $text;
}
}