Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 900483f493
Fetching contributors…

Cannot retrieve contributors at this time

301 lines (250 sloc) 8.155 kb
<?php
/**
* Daemonising base class. Does job, listents to signals. Best used under daemon control system such as supervisord
*
* @package Propeller
*
*/
abstract class EasyDaemon {
# Лимит памяти
protected $memoryLimit = '64M';
# Признак того, что пора останавливаться
protected $shouldStop = false;
# Счётчик секунд
protected $counter;
protected $lastTime = 0;
# Время одижания между итерациями
protected $sleepTime = 1;
# Максимальное время жизни
protected $maxLifeTime = 0;
# Режим отладки
protected $debugLevel = 0;
# Интервалы времени
protected $periods = array(
's' => array(),
'm' => array(),
'h' => array(),
);
protected $secondPeriods = array();
protected $secondPeriodsLast = array();
protected $minutePeriods = array();
protected $minutePeriodsLast = array();
protected $hourPeriods = array();
protected $hourPeriodsLast = array();
protected $day;
# Обработчики сигналов
protected $_sigHandlers = array(
SIGHUP => array('EasyDaemon', 'restart'),
SIGINT => array('EasyDaemon', 'defaultSigHandler'),
SIGQUIT => array('EasyDaemon', 'defaultSigHandler'),
SIGILL => array('EasyDaemon', 'defaultSigHandler'),
SIGTRAP => array('EasyDaemon', 'defaultSigHandler'),
SIGABRT => array('EasyDaemon', 'defaultSigHandler'),
SIGIOT => array('EasyDaemon', 'defaultSigHandler'),
SIGBUS => array('EasyDaemon', 'defaultSigHandler'),
SIGFPE => array('EasyDaemon', 'defaultSigHandler'),
SIGUSR1 => array('EasyDaemon', 'defaultSigHandler'),
SIGSEGV => array('EasyDaemon', 'defaultSigHandler'),
SIGUSR2 => array('EasyDaemon', 'defaultSigHandler'),
SIGPIPE => SIG_IGN,
SIGALRM => array('EasyDaemon', 'defaultSigHandler'),
SIGTERM => array('EasyDaemon', 'stop'),
SIGCONT => array('EasyDaemon', 'defaultSigHandler'),
SIGTSTP => array('EasyDaemon', 'defaultSigHandler'),
SIGTTIN => array('EasyDaemon', 'defaultSigHandler'),
SIGTTOU => array('EasyDaemon', 'defaultSigHandler'),
SIGURG => array('EasyDaemon', 'defaultSigHandler'),
SIGXCPU => array('EasyDaemon', 'defaultSigHandler'),
SIGXFSZ => array('EasyDaemon', 'defaultSigHandler'),
SIGVTALRM => array('EasyDaemon', 'defaultSigHandler'),
SIGPROF => array('EasyDaemon', 'defaultSigHandler'),
SIGWINCH => array('EasyDaemon', 'defaultSigHandler'),
SIGIO => array('EasyDaemon', 'defaultSigHandler'),
SIGBABY => array('EasyDaemon', 'defaultSigHandler'),
SIG_BLOCK => array('EasyDaemon', 'defaultSigHandler'),
SIG_UNBLOCK => array('EasyDaemon', 'defaultSigHandler'),
SIG_SETMASK => array('EasyDaemon', 'defaultSigHandler'),
);
/**
* Конструктор
*/
public function __construct($options = null) {
$this->setMemoryLimit();
for($i = 1; $i <= 60; $i++) {
$this->periods['s'][$i] = array('value' => 0, 'last' => 0);
$this->periods['m'][$i] = array('value' => 0, 'last' => 0);
}
for($i = 1; $i <= 24; $i++) {
$this->periods['h'][$i] = array('value' => 0, 'last' => 0);
}
$this->init();
}
/**
* Абстрактный метод, содержаний полезную работу
*/
abstract function job();
abstract function init();
/**
* Между работой
*
*/
public function betweenJob() {
if($this->debugLevel) echo '*';
}
/**
* Устанавливает обработчик сигнала
*
* @param int $signal номер сигнала
* @param ref $handler ссылка на обработчик
*/
public function setSigHandler($signal, $handler) {
if (!isset($this->_sigHandlers[$signal])) {
$this->sendError('Invalid signal number');
}
self::$_sigHandlers[$signal] = $handler;
return true;
}
/**
* Включение-выключение режима отладки
*
* @param boolean $mode
*/
public function setDebugLevel($mode) {
$this->debugLevel = $mode;
}
/**
* Вывод отладочной информации
*
*/
public function debug($msg) {
if ($this->debugLevel) echo $msg . "\n";
}
/**
* Enter description here...
*
* @param string $limit лимит в виде строки (128М)
*/
public function setMemoryLimit($limit = null) {
if($limit !== null) $this->memoryLimit = $limit;
ini_set('memory_limit', $this->memoryLimit);
}
/**
* Обработчик сигналов по-умолчанию
*
* @param int @sigNo номер сигнала
*/
public function defaultSigHandler($sigNo) {
switch ($sigNo) {
case SIGTERM:
case SIGINT:
$this->stop();
break;
case SIGHUP:
// Handle restart tasks
$this->restart();
break;
default:
// Handle all other signals
break;
}
}
/**
* Цикл основного метода
*/
public function run() {
declare(ticks = 1);
foreach ($this->_sigHandlers as $signal => $handler) {
if($signal) {
if (!is_callable($handler) && $handler != SIG_IGN && $handler != SIG_DFL) {
$this->_sendError('Uncallable signal');
} else if (!pcntl_signal($signal, $handler)) {
$this->_sendError('Unable to reroute signal handler (' . $signal . ')');
}
}
}
while(!$this->shouldStop) {
$this->job();
$this->betweenJob();
$this->checkTime();
# Пользовательский метод простоя или же просто пауза
if(method_exists($this, 'onIdle')) {
$this->onIdle();
} else {
sleep($this->sleepTime);
}
# Надо умирать?
if($this->maxLifeTime && $this->maxLifeTime < $this->counter) break;
}
}
/**
* Работа со временем
*/
public function checkTime() {
$this->counter += time() - $this->lastTime;
if($this->counter > 86400) {
$this->counter = 0;
$this->day = 1;
} else {
$this->day = 0;
}
# Секундные интервалы
for($s = 1; $s <= 60; $s++) {
if(!$this->counter) $this->secondPeriodsLast[$s] = 0;
if(intval($this->counter / $s) && intval($this->counter / $s) > $this->periods['s'][$s]['last']) {
$this->periods['s'][$s]['value'] = 1;
$this->periods['s'][$s]['last'] = intval($this->counter / $s);
} else {
$this->periods['s'][$s]['value'] = 0;
}
}
# Минутные
for($m = 1; $m <= 60; $m++) {
if(!$this->counter) $this->periods['m'][$m]['lasts'] = 0;
if(intval($this->counter / ($m * 60)) && intval($this->counter / ($m * 60)) > $this->periods['m'][$m]['last']) {
$this->periods['m'][$m]['value'] = 1;
$this->periods['m'][$m]['last'] = intval($this->counter / ($m * 60));
} else {
$this->periods['m'][$m]['value'] = 0;
}
}
# Часовые
for($h = 1; $h <= 24; $h++) {
if(!$this->counter) $this->periods['h'][$h]['last'] = 0;
if(intval($this->counter / ($h * 3600)) > $this->periods['h'][$h]['last']) {
$this->periods['h'][$h]['value'] = 1;
$this->periods['h'][$h]['last'] = intval($this->counter / ($h * 3600));
} else {
$this->periods['h'][$h]['value'] = 0;
}
}
$this->lastTime = time();
}
/**
* Остановиться
*/
public function stop() {
$this->shouldStop = true;
}
/**
* Обработчик сигнала HUP
*/
public function restart() {
}
/**
* Задать время ожидания в холостом цикле
*
* @param unknown_type $s
*/
public function setSleepTime($s) {
$this->sleepTime = $s;
}
/**
* Вывод ошибок
*
* @param string $message текст ошибки
*/
protected function _sendError($message) {
err($message);
}
}
?>
Jump to Line
Something went wrong with that request. Please try again.