Гость
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / PHP-скрипт в режиме демона / 12 сообщений из 12, страница 1 из 1
22.09.2020, 09:13
    #40001174
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
У меня есть PHP-скрипт, который бы хотелось запустить в режиме постоянной активности.
Не подскажите, как это можно сделать?
Желательно, чтобы он умел реагировать на сигналы.
И чтобы в режиме ожидания он не потреблял много ресурсов (то есть sleep в цикле не лучший способ).
...
Рейтинг: 0 / 0
22.09.2020, 12:14
    #40001240
PHP-скрипт в режиме демона
либо так
либо так
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
#!/usr/bin/php

<?php
// Игнорирует отключение пользователя и позволяет скрипту быть запущенным постоянно
ignore_user_abort(true);
set_time_limit(0);

echo 'Тестирование управления соединением PHP';

// Запуск бесконечного цикла, который будет завершен при выходе со страницы либо при нажатии кнопки "Stop".
while(true)
{
    // Завершено ли соединение?
    if(connection_status() != CONNECTION_NORMAL)
    {
        break;
    }

    // работа тут

    // Пауза на 10 секунд
    sleep(10);
}

// Если скрипт достиг этой строки, то была выполнена функция 'break' из цикла while
// Здесь можно производить журналирование, либо выполнять другие необходимые операции независимо от браузера.
...
Рейтинг: 0 / 0
22.09.2020, 12:15
    #40001241
PHP-скрипт в режиме демона
Alibek B.
то есть sleep в цикле не лучший способ

лучший.
...
Рейтинг: 0 / 0
22.09.2020, 13:13
    #40001268
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Скрипт работает в консоли, поэтому отключать реакцию на Ctrl+C не нужно.
Наоборот, я добавил свои обработчики на SIG.
Но в цикле со sleep у меня на холостом цикле была вполне заметная нагрузка на CPU.

А под "как это можно сделать" я имел ввиду не управление событиями в скрипте, а скорее техническую реализацию.
Можно конечно просто запускать через nohup, но если есть какой-то штатный способ сделать демон из скрипта, то я бы предпочел его.
...
Рейтинг: 0 / 0
22.09.2020, 13:35
    #40001278
PHP-скрипт в режиме демона
в гугле полно реализаций
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
#!/usr/bin/env php

<?php

/* ПРОСТЕЙШИЙ ДЕМОН
1. Cброс маски режимов создания файлов в 0 функцией umask(), чтобы маскировать некоторые биты прав доступа от запускающего процесса.
2. Вызвать fork() и завершить родительский процесс. Это делается для того, чтоб если процесс был запущен как команда, то командная оболочка считала, что команда завершилась и в тоже время,
дочерний процесс наследует идентификатор группы процессов от родителя и получает свой свой идентификатор процесса. Таким образом гарантируется, что он не будет являтся лидером группы
процессов.
3. Создать новую сессию, вызвав setsid(). При этом процесс становится лидером новой сессии, лидером новой группы процессов и лишается управляющего терминала.
4. Сделать корневой каталог текущим рабочим каталогом, так как текущий каталог сможет быть примонтированным.
5. Закрыть все файловые дескрипторы.
6. Сделать перенаправление дескрипторов 0,1 и 2 (stdin,stdout и stderr) в /dev/null или в файлы /var/log/project_name.out потому что, некоторые стандартные библиотечные функции используют эти
дескрипторы.
7. Записать pid (идентификатор номера процесса) в pid-файл: /var/run/projectname.pid
8. Корректно обработать сигналы SigTERM и SigHUP: завершиться с уничтожением всех дочерних процессов и pid – файлов и/или перечитать конфигурацию.

Чтобы демонизировать скрипт, нужно отвязать его от консоли и пустить в бесконечный цикл. Давай посмотрим, как это делается.*/


// НАСТРОЙКИ

$s=array();
initDataKK($s);









# выход, если демон уже запущен
if(isDaemonActive()){echo"\t!!! ДЕМОН уже запущен\n";exit;}


# 1. Cброс маски режимов создания файлов в 0 функцией umask(), чтобы маскировать некоторые биты прав доступа от запускающего процесса.
umask(0);

# 2. создаем дочерний процесс
$pid = pcntl_fork(); // $pid == 0, поскольку это дочерний процесс
if($pid){exit;} // выходим из родительского, привязанного к консоли, процесса

# если ВДРУГ, по каким-то причинам, pcntl_fork() не отработал ^^
if($pid < 0){echo"\t!!! fork failed\n";exit(1);}

# 3. делаем основным процессом дочерний. После этого он тоже может плодить детей. Суровая жизнь у этих процессов...
$sid = posix_setsid(); // здесь демон получает свой собственный PID в процессах (Make the current process a session leader.)
if($sid < 0){echo"демон НЕ запущен!\n";exit(2);}else{echo"демон запущен, PID: ",$sid,"\n";}

# после демонизации — нужно записать в pid-файл текущий PID демона.
file_put_contents($s{'pidFile'},getmypid());

# 4.
chdir('/');

# 5. просто не нужно до fork() открывать какие-либо ФД
# можно напрямую переопределить STDIN,STDOUT & STDERR:
ini_set('error_log',$s{'dir'}."/error.log"); // установка лог-файла
ini_set('display_errors',1);
error_reporting(E_ALL);
// $logDir -  обычно /var/log/mydaemon
// закрываем открытые системой файловые дескрипторы stdin,stdout,stderr
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$STDIN = fopen('/dev/null','r'); // перенаправляем stdin в /dev/null
$STDOUT = fopen($s{'logF'},'ab'); // перенаправляем stdout в лог-файл
$STDERR = fopen($s{'logErrF'},'ab'); // перенаправляем stderr в лог-файл

global $stop_server;
$stop_server=false;





// После таких действий мы остаемся с демоном — программой без консоли. Чтобы она не завершила свое выполнение немедленно, пускаем ее в бесконечный цикл (ну, почти):
while($stop_server === false)
{
    // TODO: делаем что-то


// ОБРАБОТКА СИГНАЛОВ

/*
kill -l         список сигналов
Следующая по важности задача — обеспечение обработки сигналов. Сейчас наш демон ничего не знает о внешнем мире, и убить его можно только завершением процесса через kill -SIGKILL.
Это плохо. Это очень плохо — SIGKILL прервет процессы на середине. Кроме того, ему никак нельзя передать информацию.
Есть куча интересных сигналов, которые можно обрабатывать, но мы остановимся на SIGTERM — сигнале корретного завершения работы.
список: man 7 signal */
pcntl_signal_dispatch(); // Без этой директивы PHP не будет перехватывать сигналы. ДО 5.3.0 было: declare(ticks=1); хотя некоторые рекомендуют =100

pcntl_signal(SIGTERM,"sigHandler"); // регистрируем обработчик. это собственно отправка сигнала SIGTERM обработчику sigHandler
pcntl_signal(SIGHUP,"sigHandler");
pcntl_signal(SIGCHLD,"sigHandler");
# Мы можем проигнорировать сигнал, используя флаг SIG_IGN: pcntl_signal(SIGHUP, SIG_IGN); Или, при необходимости, востановить обработчик сигнала, используя флаг SIG_DFL,
# который ранее был установлен по умолчанию: pcntl_signal(SIGHUP, SIG_DFL);

# Вот и все. Мы перехватываем сигнал — ставим флаг в скрипте — используем этот флаг, чтоб не запускать новые потоки и завершить основной цикл.


sleep($s{'tick'}); // !!! ОБЯЗАТЕЛЬНО !!! иначе 100% загрузки проца ))

}

echo"вот\n";


function sigHandler($signo){ // ОБРАБОТЧИК СИГНАЛОВ

global $s;

switch($signo)
{
    case SIGTERM:
    {
        $stop_server = true;
        echo"SIGTERM остановка демона...\n";
        breakIt();
        exit;
        break;
    }
    case SIGHUP:
    {
        echo"SIGHUP остановка демона...\n";
        initDataKK($s); // перечитать конфиг
        exit;
    }
    case SIGCHLD:
    {
        echo"сигнал дочки\n";
        break;
    }
    default:
    {
        //все остальные сигналы
        echo"все остальные сигналы\n";
    }
}

} // sigHandler

function breakIt(){ // убить демона

global $s;
unlink($s{'pidFile'})or die("что за нах??\n");

} // breakIt

function isDaemonActive(){

global $s;

if(is_file($s{'pidFile'}))
{
    $pid = file_get_contents($s{'pidFile'});
    echo$pid,"\n";
    //проверяем на наличие процесса
    if(posix_kill($pid,0))
        {return true;} // демон уже запущен
    else // pid-файл есть, но процесса нет = уничтожить pid-файл, а если не могу, то ошибка
        {if(!unlink($s{'pidFile'})){echo"уничтожить pid-файл\n";exit(-1);}}
}

return false;

}

function initDataKK(&$s){

$s=array(
'dir'           =>'/usr/dork/base/PHP/daemons',
'logDir'        =>'/usr/dork/base/PHP/daemons', // дира логов
'tick'          =>3, // как часто демон "тикает" (иначе 100% загрузки проца)
);
$s{'logF'}=$s{'dir'}.'/application.log'; // лог-файл
$s{'logErrF'}=$s{'dir'}.'/application-error.log'; // лог ошибок
$s{'pidFile'}=$s{'dir'}.'/daemon1.pid'; // PID-файл

} // initDataKK
...
Рейтинг: 0 / 0
23.09.2020, 18:15
    #40001808
ShSerge
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Alibek B.,

А через амперсанд не годится?
Например:
php myscript.php&
...
Рейтинг: 0 / 0
20.10.2020, 17:32
    #40010245
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Не могу понять, что не так.
Скрипт вроде бы работает, но при запуске в режиме демона завершается.
То есть запускаю его с ключом start, он запускается, выводит pid.
Но затем процесса с этим pid, он уже завершен.

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
# Конфигурационные параметры
$_cfg = [];
$_cfg['name'] = basename(__FILE__, '.php');
$_cfg['base'] = __DIR__ . "/{$_cfg['name']}";
$_cfg['log'] = "{$_cfg['base']}/{$_cfg['name']}.log";
$_cfg['err'] = "{$_cfg['base']}/{$_cfg['name']}.err";
$_cfg['act'] = "{$_cfg['base']}/{$_cfg['name']}.act";
$_cfg['pid'] = "{$_cfg['base']}/{$_cfg['name']}.pid";
$_cfg['tick'] = 5;

# Определение режима запуска
$mode = null;
if (isset($argv) && isset($argv[1])) $mode = $argv[1];
switch ($mode)
{
	case "test":
	case "debug":
	case "start":
	case "stop":
	case "reload":
	case "status":
		break;
	default:
		$mode = null;
}
if (!isset($mode)) _help();
function _help()
{
	global $_cfg;
	print "Usage: {$_cfg['name']} <mode>\n";
	print "  <mode>: \n";
	print "          test   - interactive mode\n";
	print "          debug  - interactive mode with debug\n";
	print "          start  - daemon mode starting\n";
	print "          stop   - daemon mode stopping\n";
	print "          reload - reload settings\n";
	print "          status - daemon mode status\n";
	print "Base dir: {$_cfg['base']}\n";
	exit;
}

# Состояние выполнения
$_run = [];
$_run['mode'] = $mode;
$_run['debug'] = ($mode == 'debug');
$_run['daemon'] = ($mode == 'start');
$_run['pid'] = null;
$_run['start'] = time();
$_run['stop'] = null;
if (is_file($_cfg['pid']))
{
	$pid = file_get_contents($_cfg['pid']);
	if ($pid)
	{
		if (posix_kill($pid, 0))
		{
			$_run['pid'] = $pid;
		}
	}
}

# Вывод форматированной строки
function _out($type=null, $str=null, $arg=null)
{
	global $_cfg, $_run;
	$s = date('Ymd\-His').': ';
	switch ($type)
	{
		case 'crit':
		case 'fail':
			$type = 'fail';
			$s .= "! ";
			break;
		case 'warn':
		case 'err':
			$type = 'err';
			$s .= "* ";
			break;
		case 'info':
			$type = 'info';
			$s .= "- ";
			break;
		case 'ok':
			$type = 'ok';
			$s .= "+ ";
			break;
		case 'dbg':
		case 'debug':
			$type = 'dbg';
			$s .= "# ";
			break;
		default:
			$type = null;
			$s .= "  ";
	}
	$s .= (isset($arg) ? @vsprintf($str, $arg) : $str) . "\n";
	if (($type == 'dbg') && !$_run['debug']) return;
	if (!isset($type) && !isset($str)) $s = "\n";
	print $s;
}

# Обработчик сигналов
function _sig($sig)
{
	global $_cfg, $_run;
	switch($sig)
	{
		case SIGTERM:
			$_run['stop'] = time();
			_out('info', '%1s - stop pending...', [$_cfg['name']]);
			break;
		case SIGHUP:
			_out('info', '%1s - reloading (HUP)...', [$_cfg['name']]);
			_init();
			break;
		case SIGINT:
			$_run['stop'] = time();
			_out('info', '%1s - break pending...', [$_cfg['name']]);
			break;
		case SIGCHLD:
			_out('info', '%1s - reloading (CHILD)...', [$_cfg['name']]);
			_init();
			break;
		default:
			_out('info', '%1s - signal %2d received', [$_cfg['name'], $sig]);
	}
}

# Запуск в режиме демона
function _start()
{
	global $_cfg, $_run;
	umask(0);
	$pid = pcntl_fork();
	if ($pid < 0) {
		_out('fail', '%1s - fork failed!', [$_cfg['name']]);
		exit;
	} elseif ($pid) {
		exit;
	}
	$sid = posix_setsid();
	if ($sid < 0) {
		_out('fail', '%1s - install failed!', [$_cfg['name']]);
		exit;
	}
	_out('ok', '%1s - started, PID: %2d', [$_cfg['name'], $sid]);
	file_put_contents($_cfg['pid'],getmypid());
	_out('dbg', 'Prepare environment...');
	chdir('/');
	ini_set('error_log', $_cfg['log']);
	ini_set('display_errors', 1);
	error_reporting(E_ALL);
	fclose(STDIN);
	fclose(STDOUT);
	fclose(STDERR);
	$STDIN = fopen('/dev/null','r');
	$STDOUT = fopen($_cfg['log'],'ab');
	$STDERR = fopen($_cfg['err'],'ab');
}

# Остановка демона
function _stop()
{
	global $_cfg, $_run;
	if ($_run['pid'])
	{
		$rc = @unlink($_cfg['pid']);
		_out(($rc ? 'ok' : 'err'), '%1s - ' . ($rc ? 'stopped' : 'stop failed!'), [$_cfg['name']]);
	}
	else
	{
		if (is_file($_cfg['pid'])) @unlink($_cfg['pid']);
	}
	exit;
}

# Получение статуса
function _status()
{
	global $_cfg, $_run;
	_out(null, '%1s - ' . ($_run['pid'] ? 'running, PID: %2d' : 'not running'), [$_cfg['name'], $_run['pid']]);
}

# Инициализация данных
function _init()
{
	global $_cfg, $_run;
	_out(null, 'Initialize script data');
}

# Основная обработка
function _proc()
{
	global $_cfg, $_run;
	_out(null, 'proc');
}

print_r($_cfg);
print_r($_run);

switch ($_run['mode'])
{
	case "test":
	case "debug":
		if ($_run['pid'])
		{
			_out('info', '%1s - already running in daemon mode, PID: %2d', [$_cfg['name'], $_run['pid']]);
			exit;
		}
		_out('info', '%1s - run int standalone mode', [$_cfg['name']]);
		break;
	case "start":
		if ($_run['pid'])
		{
			_out('info', '%1s - already running in daemon mode, PID: %2d', [$_cfg['name'], $_run['pid']]);
			exit;
		}
		break;
	case "stop":
		if (!$_run['pid'])
		{
			_out('info', '%1s - not running', [$_cfg['name']]);
			exit;
		}
		posix_kill($_run['pid'], SIGTERM);
		exit;
		break;
	case "reload":
		if (!$_run['pid'])
		{
			_out('info', '%1s - not running', [$_cfg['name']]);
			exit;
		}
		posix_kill($_run['pid'], SIGHUP);
		exit;
		break;
	case "status":
		_status();
		exit;
		break;
	default:
		_out('err', '%1s - unknown mode', [$_cfg['name']]);
		exit;
		break;
}

if ($_run['daemon']) _start();
_out('dbg', 'Set signal handler...');
pcntl_signal_dispatch();
pcntl_signal(SIGTERM, "_sig");
pcntl_signal(SIGHUP, "_sig");
pcntl_signal(SIGINT, "_sig");
pcntl_signal(SIGCHLD, "_sig");
_init();
while (!isset($_run['stop']))
{
	_proc();
	sleep($_cfg['tick']);
}
if ($_run['daemon']) _stop();

...
Рейтинг: 0 / 0
20.10.2020, 20:19
    #40010316
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Такое впечатление, что форк после завершения текущей процедуры тут же завершает свою работу.
Процедура _start выполняется, а от основное тело программы после этой процедуры уже нет.
Вместо вызова _start написал код прямо в теле основной программы — так все работает.
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
if ($_run['daemon']) //_start();
{
	umask(0);
	$pid = pcntl_fork();
	if ($pid < 0) {
		_out('fail', '%1s - fork failed!', [$_cfg['name']]);
		exit;
	} elseif ($pid) {
		exit;
	}
	$sid = posix_setsid();
	if ($sid < 0) {
		_out('fail', '%1s - install failed!', [$_cfg['name']]);
		exit;
	}
	_out('ok', '%1s - started, PID: %2d', [$_cfg['name'], $sid]);
	$_run['pid'] = getmypid();
	file_put_contents($_cfg['pid'], $_run['pid']);
	_out('dbg', 'Prepare environment...');
	chdir('/');
	ini_set('error_log', $_cfg['log']);
	ini_set('display_errors', 1);
	error_reporting(E_ALL);
	fclose(STDIN);
	fclose(STDOUT);
	fclose(STDERR);
	$STDIN = fopen('/dev/null','r');
	$STDOUT = fopen($_cfg['log'],'ab');
	$STDERR = fopen($_cfg['err'],'ab');
}



Так и должно быть?
...
Рейтинг: 0 / 0
20.10.2020, 20:33
    #40010323
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Финальный каркас скрипта-демона.
Может запускаться как в режиме демона, так и в интерактивном (тестовом) режиме.

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
# Конфигурационные параметры
$_cfg = [];
$_cfg['name'] = basename(__FILE__, '.php');
$_cfg['base'] = __DIR__ . "/{$_cfg['name']}";
$_cfg['log'] = "{$_cfg['base']}/{$_cfg['name']}.log";
$_cfg['err'] = "{$_cfg['base']}/{$_cfg['name']}.err";
$_cfg['act'] = "{$_cfg['base']}/{$_cfg['name']}.act";
$_cfg['pid'] = "{$_cfg['base']}/{$_cfg['name']}.pid";
$_cfg['tick'] = 5;

# Определение режима запуска
$mode = null;
if (isset($argv) && isset($argv[1])) $mode = $argv[1];
switch ($mode)
{
	case "test":
	case "debug":
	case "start":
	case "stop":
	case "reload":
	case "status":
		break;
	default:
		$mode = null;
}
if (!isset($mode)) _help();
function _help()
{
	global $_cfg;
	print "Usage: {$_cfg['name']} <mode>\n";
	print "  <mode>: \n";
	print "          test   - interactive mode\n";
	print "          debug  - interactive mode with debug\n";
	print "          start  - daemon mode starting\n";
	print "          stop   - daemon mode stopping\n";
	print "          reload - reload settings\n";
	print "          status - daemon mode status\n";
	print "Base dir: {$_cfg['base']}\n";
	exit;
}

# Состояние выполнения
$_run = [];
$_run['mode'] = $mode;
$_run['debug'] = ($mode == 'debug');
$_run['daemon'] = ($mode == 'start');
$_run['pid'] = null;
$_run['start'] = time();
$_run['stop'] = null;
if (is_file($_cfg['pid']))
{
	$pid = file_get_contents($_cfg['pid']);
	if ($pid)
	{
		if (posix_kill($pid, 0))
		{
			$_run['pid'] = $pid;
		}
	}
}

# Вывод форматированной строки
function _out($type=null, $str=null, $arg=null)
{
	global $_cfg, $_run;
	$s = date('Ymd\-His').': ';
	switch ($type)
	{
		case 'crit':
		case 'fail':
			$type = 'fail';
			$s .= "! ";
			break;
		case 'warn':
		case 'err':
			$type = 'err';
			$s .= "* ";
			break;
		case 'info':
			$type = 'info';
			$s .= "- ";
			break;
		case 'ok':
			$type = 'ok';
			$s .= "+ ";
			break;
		case 'dbg':
		case 'debug':
			$type = 'dbg';
			$s .= "# ";
			break;
		default:
			$type = null;
			$s .= "";
	}
	$s .= (isset($arg) ? @vsprintf($str, $arg) : $str) . "\n";
	if (($type == 'dbg') && !$_run['debug']) return;
	if (!isset($type) && !isset($str)) $s = "\n";
	print $s;
}

# Обработчик сигналов
function _sig($sig)
{
	global $_cfg, $_run;
	switch($sig)
	{
		case SIGTERM:
			$_run['stop'] = time();
			_out('info', '%1s - stop pending...', [$_cfg['name']]);
			break;
		case SIGHUP:
			_out('info', '%1s - reloading (HUP)...', [$_cfg['name']]);
			_init();
			break;
		case SIGINT:
			$_run['stop'] = time();
			_out('info', '%1s - break pending...', [$_cfg['name']]);
			break;
		case SIGCHLD:
			_out('info', '%1s - reloading (CHILD)...', [$_cfg['name']]);
			_init();
			break;
		default:
			_out('info', '%1s - signal %2d received', [$_cfg['name'], $sig]);
	}
}

# Запуск в режиме демона
function _start()
{
	global $_cfg, $_run;
/*
	# использовать в теле основной программы
	umask(0);
	$pid = pcntl_fork();
	if ($pid < 0) {
		_out('fail', '%1s - fork failed!', [$_cfg['name']]);
		exit;
	} elseif ($pid) {
		exit;
	}
	$sid = posix_setsid();
	if ($sid < 0) {
		_out('fail', '%1s - install failed!', [$_cfg['name']]);
		exit;
	}
	_out('ok', '%1s - started, PID: %2d', [$_cfg['name'], $sid]);
	$_run['pid'] = getmypid();
	file_put_contents($_cfg['pid'], $_run['pid']);
	_out('dbg', 'Prepare environment...');
	chdir('/');
	ini_set('error_log', $_cfg['log']);
	ini_set('display_errors', 1);
	error_reporting(E_ALL);
	fclose(STDIN);
	fclose(STDOUT);
	fclose(STDERR);
	$STDIN = fopen('/dev/null','r');
	$STDOUT = fopen($_cfg['log'],'ab');
	$STDERR = fopen($_cfg['err'],'ab');
*/
}

# Остановка демона
function _stop()
{
	global $_cfg, $_run;
	if ($_run['pid'])
	{
		$rc = @unlink($_cfg['pid']);
		_out(($rc ? 'ok' : 'err'), '%1s - ' . ($rc ? 'stopped' : 'stop failed!'), [$_cfg['name']]);
	}
	else
	{
		if (is_file($_cfg['pid'])) @unlink($_cfg['pid']);
	}
}

# Получение статуса
function _status()
{
	global $_cfg, $_run;
	_out(null, '%1s - ' . ($_run['pid'] ? 'running, PID: %2d' : 'not running'), [$_cfg['name'], $_run['pid']]);
}

# Инициализация данных
function _init()
{
	global $_cfg, $_run;
	_out(null, 'Initialize script data');
}

# Основная обработка
function _proc()
{
	global $_cfg, $_run;
}

switch ($_run['mode'])
{
	case "test":
	case "debug":
		if ($_run['pid'])
		{
			_out('info', '%1s - already running in daemon mode, PID: %2d', [$_cfg['name'], $_run['pid']]);
			exit;
		}
		_out('info', '%1s - run int standalone mode', [$_cfg['name']]);
		break;
	case "start":
		if ($_run['pid'])
		{
			_out('info', '%1s - already running in daemon mode, PID: %2d', [$_cfg['name'], $_run['pid']]);
			exit;
		}
		break;
	case "stop":
		if (!$_run['pid'])
		{
			_out('info', '%1s - not running', [$_cfg['name']]);
			exit;
		}
		_out('info', '%1s:%2d - send request to stop', [$_cfg['name'], $_run['pid']]);
		posix_kill($_run['pid'], SIGTERM);
		exit;
		break;
	case "reload":
		if (!$_run['pid'])
		{
			_out('info', '%1s - not running', [$_cfg['name']]);
			exit;
		}
		_out('info', '%1s:%2d - send request to reload', [$_cfg['name'], $_run['pid']]);
		posix_kill($_run['pid'], SIGHUP);
		exit;
		break;
	case "status":
		_status();
		exit;
		break;
	default:
		_out('err', '%1s - unknown mode', [$_cfg['name']]);
		exit;
		break;
}

if ($_run['daemon']) //_start();
{
	umask(0);
	$pid = pcntl_fork();
	if ($pid < 0) {
		_out('fail', '%1s - fork failed!', [$_cfg['name']]);
		exit;
	} elseif ($pid) {
		exit;
	}
	$sid = posix_setsid();
	if ($sid < 0) {
		_out('fail', '%1s - install failed!', [$_cfg['name']]);
		exit;
	}
	_out('ok', '%1s - started, PID: %2d', [$_cfg['name'], $sid]);
	$_run['pid'] = getmypid();
	file_put_contents($_cfg['pid'], $_run['pid']);
	_out('dbg', 'Prepare environment...');
	chdir('/');
	ini_set('error_log', $_cfg['log']);
	ini_set('display_errors', 1);
	error_reporting(E_ALL);
	fclose(STDIN);
	fclose(STDOUT);
	fclose(STDERR);
	$STDIN = fopen('/dev/null','r');
	$STDOUT = fopen($_cfg['log'],'ab');
	$STDERR = fopen($_cfg['err'],'ab');
}
_out('dbg', 'Set signal handler...');
declare(ticks=1);
pcntl_signal_dispatch();
pcntl_signal(SIGTERM, "_sig");
pcntl_signal(SIGHUP, "_sig");
pcntl_signal(SIGINT, "_sig");
pcntl_signal(SIGCHLD, "_sig");
_init();
while (!isset($_run['stop']))
{
	_proc();
	sleep($_cfg['tick']);
}
if ($_run['daemon']) _stop();
if (!isset($_run['stop'])) $_run['stop'] = time();
_out('info', '%1s quit, work time %2d second(s).', [$_cfg['name'], $_run['stop']-$_run['start']]);

...
Рейтинг: 0 / 0
21.10.2020, 13:11
    #40010465
ScareCrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
что люди не делают лишь бы доку по symfony process не читать
...
Рейтинг: 0 / 0
21.10.2020, 14:09
    #40010494
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Просто не вижу необходимости в фреймворке, который нужно запускать и настраивать, когда у меня сервисный скрипт под конкретную задачу.
...
Рейтинг: 0 / 0
21.10.2020, 14:59
    #40010515
ScareCrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
PHP-скрипт в режиме демона
Alibek B.
Просто не вижу необходимости в фреймворке, который нужно запускать и настраивать, когда у меня сервисный скрипт под конкретную задачу.


Symfony is a set of reusable PHP components.... Choose any of the 50 stand-alone components available for your own applications.
...
Рейтинг: 0 / 0
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / PHP-скрипт в режиме демона / 12 сообщений из 12, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]