Мне нужно запустить php script в качестве процесса демона (дождаться инструкций и сделать что-нибудь). Работа cron не будет делать это для меня, потому что действия должны быть приняты, как только придет инструкция. Я знаю, что PHP не самый лучший вариант для процессов-демонов из-за проблем с управлением памятью, но по разным причинам я должен использовать PHP в этом случае. Я наткнулся на инструмент libslack под названием Daemon (http://libslack.org/daemon), похоже, помогает мне управлять процессами демона, но обновлений не было за последние 5 лет, так что я задаюсь вопросом, знаете ли вы другие альтернативы, подходящие для моего дела. Любая информация будет действительно оценена.
Запустите PHP скрипт как процесс демона
Ответ 1
Вы можете запустить свой php script из командной строки (т.е. bash) с помощью
nohup php myscript.php &
&
помещает ваш процесс в фоновый режим.
Edit:
Да, есть некоторые недостатки, но невозможно контролировать? Это просто неправильно.
Простой kill processid
остановит его. И это все еще самое лучшее и самое простое решение.
Ответ 2
Другой вариант - использовать Upstart. Он был первоначально разработан для Ubuntu (и поставляется с ним по умолчанию), но предназначен для всех дистрибутивов Linux.
Этот подход похож на Supervisord и daemontools, поскольку он автоматически запускает демона при загрузке системы и респаунах на завершение script.
Как настроить:
Создайте новый script файл в /etc/init/myphpworker.conf
. Вот пример:
# Info
description "My PHP Worker"
author "Jonathan"
# Events
start on startup
stop on shutdown
# Automatically respawn
respawn
respawn limit 20 5
# Run the script!
# Note, in this example, if your PHP скрипт returns
# the string "ERROR", the daemon will stop itself.
script
[ $(exec /usr/bin/php -f /path/to/your/script.php) = 'ERROR' ] && ( stop; exit 1; )
end script
Запуск и остановка вашего демона:
sudo service myphpworker start
sudo service myphpworker stop
Проверьте, запущен ли ваш демон:
sudo service myphpworker status
Спасибо
Большое спасибо Кевину ван Зонневельду, где я узнал эту технику.
Ответ 3
Если вы можете - возьмите копию Advanced Programming в среде UNIX. Вся глава 13 посвящена программированию демонов. Примеры написаны на C, но все нужные вам функции имеют оболочки в PHP (в основном расширения pcntl и posix).
В двух словах - написание демона (это возможно только на ОС * nix - Windows использует службы) выглядит так:
- Вызовите
umask(0)
для предотвращения проблем с разрешениями. -
fork()
и родительский выход. - Вызовите
setsid()
. - Настройте обработку сигналов
SIGHUP
(обычно это игнорируется или используется для подачи сигнала демону для перезагрузки его конфигурации) иSIGTERM
(чтобы сообщить процессу о корректном завершении работы). -
fork()
снова и родительский выход. - Измените текущий рабочий каталог с помощью
chdir()
. -
fclose()
stdin
,stdout
иstderr
и не пишите им. Правильный способ - перенаправить их в/dev/null
или в файл, но я не смог найти способ сделать это в PHP. Когда вы запускаете демон, возможно, перенаправить его с помощью оболочки (вам придется самому выяснить, как это сделать, я не знаю :). - Ты работаешь!
Кроме того, поскольку вы используете PHP, будьте осторожны с циклическими ссылками, так как сборщик мусора PHP, до PHP 5.3, не имел возможности собирать эти ссылки, и процесс будет иметь утечку памяти до тех пор, пока в конечном итоге не произойдет сбой.
Ответ 4
С новым systemd вы можете создать сервис.
Вы должны создать файл или символическую ссылку в /etc/systemd/system/
, например. myphpdaemon.service и разместите контент, подобный этому, myphpdaemon будет названием службы:
[Unit]
Description=My PHP Daemon Service
#May your script needs MySQL or other services to run, eg. MySQL Memcached
Requires=mysqld.service memcached.service
After=mysqld.service memcached.service
[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/myphpdaemon.pid
ExecStart=/usr/bin/php -f /srv/www/myphpdaemon.php arg1 arg2> /dev/null 2>/dev/null
#ExecStop=/bin/kill -HUP $MAINPID #It the default you can change whats happens on stop command
#ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
StandardOutput=null #If you don't want to make toms of logs you can set it null if you sent a file or some other options it will send all php output to this one.
StandardError=/var/log/myphpdaemon.log
[Install]
WantedBy=default.target
Вы сможете запускать, получать статус, перезапускать и останавливать сервисы, используя команду
systemctl <start|status|restart|stop|enable> myphpdaemon
PHP-скрипт должен иметь своего рода "цикл" для продолжения работы.
<?php
gc_enable();//
while (!connection_aborted() || PHP_SAPI == "cli") {
//Code Logic
//sleep and usleep could be useful
if (PHP_SAPI == "cli") {
if (rand(5, 100) % 5 == 0) {
gc_collect_cycles(); //Forces collection of any existing garbage cycles
}
}
}
Рабочий пример:
[Unit]
Description=PHP APP Sync Service
Requires=mysqld.service memcached.service
After=mysqld.service memcached.service
[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/php_app_sync.pid
ExecStart=/bin/sh -c '/usr/bin/php -f /var/www/app/private/server/cron/app_sync.php 2>&1 > /var/log/app_sync.log'
KillMode=mixed
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=default.target
Если ваша подпрограмма PHP должна выполняться один раз в цикле (например, дайджест), вы можете использовать сценарий оболочки или bash для вызова в служебный файл systemd вместо PHP напрямую, например:
#!/usr/bin/env bash
script_path="/app/services/"
while [ : ]
do
# clear
php -f "$script_path"${1}".php" fixedparameter ${2} > /dev/null 2>/dev/null
sleep 1
done
Если вы выбрали эту опцию, вы должны изменить KillMode на mixed
с процессами, bash (main) и PHP (child) будут убиты.
ExecStart=/app/phpservice/runner.sh phpfile parameter > /dev/null 2>/dev/null
KillMode=process
This method also is effective if you're facing a memory leak.
Примечание. Каждый раз, когда вы меняете свой "myphpdaemon.service", вы должны запускать "systemctl daemon-reload", но если вы этого не сделаете, не забудьте, он будет предупрежден, когда это необходимо.
Ответ 5
Я запускаю большое количество демонов PHP.
Я согласен с вами в том, что PHP не лучший (или даже хороший) язык для этого, но демоны используют общий код с компонентами, ориентированными на веб-интерфейс, поэтому в целом это хорошее решение для нас.
Мы используем для этого daemontools. Это умный, чистый и надежный. Фактически мы используем его для запуска всех наших демонов.
Вы можете проверить это на http://cr.yp.to/daemontools.html.
EDIT: быстрый список функций.
- Автоматически запускает демон при перезагрузке
- Автоматический перезапуск dameon при сбое
- Ведение журнала выполняется для вас, включая опрокидывание и обрезку
- Интерфейс управления: 'svc' и 'svstat'
- UNIX-friendly (не плюс для всех)
Ответ 6
Вы можете
- Используйте
nohup
, как предложил Хенрик. - Используйте
screen
и запускайте свою PHP-программу как обычный процесс внутри этого. Это дает вам больше контроля, чем при использованииnohup
. - Используйте daemoniser, например http://supervisord.org/ (он написан на Python, но может демонтировать любую программу командной строки и дать вам удаленный элемент управления для управления им).
- Напишите свою собственную оболочку демона, как предположил Эмиль, но она перехитрила IMO.
Я бы порекомендовал простейший метод (экран, на мой взгляд), а затем, если вы хотите больше функций или функций, переходите к более сложным методам.
Ответ 7
Существует несколько способов решения этой проблемы.
Я не знаю специфики, но, возможно, есть еще один способ вызвать процесс PHP. Например, если вам нужен код для запуска на основе событий в базе данных SQL, вы можете настроить триггер для выполнения script. Это действительно легко сделать в PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html.
Честно говоря, я считаю, что лучше всего создать процесс Дэймона, используя nohup. nohup позволяет команде продолжать выполнение даже после выхода пользователя из системы:
nohup php myscript.php &
Однако существует очень серьезная проблема. Как вы сказали, диспетчер памяти PHP является полным мусором, он был построен с предположением, что script выполняется всего несколько секунд, а затем существует. Ваш PHP скрипт начнет использовать GIGABYTES памяти через несколько дней. Вы также должны создать cron script, который запускается каждые 12 или, возможно, 24 часа, что убивает и повторно запускает ваш PHP скрипт следующим образом:
killall -3 php
nohup php myscript.php &
Но что, если script находился посреди работы? Убит kill -3 - это прерывание, то же самое, что и ctrl + c в CLI. Ваш PHP скрипт может поймать это прерывание и изящно выйти из библиотеки PHP pcntl: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php
Вот пример:
function clean_up() {
GLOBAL $lock;
mysql_close();
fclose($lock)
exit();
}
pcntl_signal(SIGINT, 'clean_up');
Идея блокировки $состоит в том, что PHP script может открыть файл с fopen ( "file", "w" );. Только один процесс может иметь блокировку записи в файле, поэтому, используя это, вы можете убедиться, что работает только одна копия вашего PHP скрипт.
Удачи!
Ответ 8
Kevin van Zonneveld написал очень хорошую подробную статью об этом, в своем примере он использует System_Daemon
пакет PEAR (последняя дата выпуска 2009-09-02).
Ответ 9
Отъезд https://github.com/shaneharter/PHP-Daemon
Это объектно-ориентированная библиотека демона. Он имеет встроенную поддержку таких функций, как ведение журнала и восстановление ошибок, а также поддержка создания фоновых работников.
Ответ 10
Недавно мне понадобилось кросс-платформенное решение (Windows, Mac и Linux) на проблему запуска PHP-скриптов в качестве демонов. Я решил проблему, написав собственное решение на С++ и создав двоичные файлы:
https://github.com/cubiclesoft/service-manager/
Полная поддержка Linux (через sysvinit), но также службы Windows NT и запуск Mac OSX.
Если вам просто нужен Linux, то пара других решений, представленных здесь, работает достаточно хорошо и, в зависимости от вкуса. В наши дни также есть Upstart и systemd, которые имеют резервные копии для скриптов sysvinit. Но половина смысла использования PHP заключается в том, что он носит кросс-платформенный характер, поэтому код, написанный на этом языке, имеет очень хорошие шансы работать везде как есть. Недостатки начинают появляться, когда некоторые внешние внешние аспекты уровня OS входят в изображение, например, в системные службы, но вы получите эту проблему с большинством языков сценариев.
Попытка поймать сигналы, поскольку кто-то здесь предложил в PHP userland, не является хорошей идеей. Внимательно прочитайте документацию на pcntl_signal()
, и вы быстро узнаете, что PHP обрабатывает сигналы с использованием некоторых довольно неприятных методов (в частности, "тиков" ), которые пережевывают кучу циклов для чего-то, что редко встречается в процессах (т.е. Сигналов). Обработка сигналов в PHP также доступна только на платформах POSIX, а поддержка отличается от версии PHP. Первоначально это звучит как достойное решение, но оно не очень полезно.
PHP также улучшает проблемы с утечкой памяти с течением времени. Вы все еще должны быть осторожны (парсер DOM XML имеет тенденцию течь все еще), но я редко вижу процессы побега в эти дни, а трекер ошибок PHP довольно тихий по сравнению с днями ожидания.
Ответ 11
Как уже упоминалось, запуск PHP как демона довольно прост и может быть выполнен с использованием одной строки команды. Но актуальной проблемой является ее поддержание и управление им. Некоторое время назад у меня была та же проблема, и хотя есть много доступных решений, большинство из них имеют множество зависимостей или их трудно использовать и не подходят для основных применений. Я написал оболочку script, которая может управлять любым процессом/приложением, включая скрипты PHP cli. Он может быть установлен как cronjob для запуска приложения и будет содержать приложение и управлять им. Если он выполняется снова, например, через один и тот же cronjob, он проверяет, работает ли приложение или нет, если он делает это, то просто выходит и позволяет предыдущему экземпляру продолжить управление приложением.
Я загрузил его в github, не стесняйтесь использовать его: https://github.com/sinasalek/EasyDeamonizer
EasyDeamonizer
Просто наблюдает за вашим приложением (запуск, перезапуск, журнал, мониторинг и т.д.). общий script, чтобы убедиться, что ваше приложение остается работоспособным. Преднамеренно он использует имя процесса instread для файла pid/lock для предотвращения всех его побочных эффектов и поддерживает script как можно более простое и максимально возможное перемещение, поэтому оно всегда работает даже при перезапуске самого EasyDaemonizer. Особенности
- Запускает приложение и, возможно, настраиваемую задержку для каждого запуска
- Уверен, что работает только один экземпляр
- Мониторинг использования ЦП и перезапуск приложения автоматически, когда он достигает определенного порога
- Настройка EasyDeamonizer для запуска через cron, чтобы запустить его снова, если он остановился по любой причине
- Зарегистрирует свою деятельность
Ответ 12
Расширяя ответ Эмиля Иваова, Вы можете сделать следующее, чтобы закрыть STDIN, STDOUT И STDERROR в php
if (!fclose(STDIN)) {
exit("Could not close STDIN");
}
if (!fclose(STDOUT)) {
exit("Could not close STDOUT");
}
if (!fclose(STDERR)) {
exit("Could not close STDERR");
}
$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/var/log/our_error.log', 'wb');
По сути, вы закрываете стандартные потоки, так что PHP некуда писать. Следующие вызовы fopen
установят стандартный ввод /dev/null
вывод в /dev/null
.
Я прочитал это из книги Роба Алея - PHP вне Интернета
Ответ 13
Я написал и развернул простой php-демон, код здесь онлайн.
https://github.com/jmullee/PhpUnixDaemon
Особенности: сброс привилегий, обработка сигналов, ведение журнала
Я использовал его в обработчике очереди (прецедент: триггер длительной операции с веб-страницы, без необходимости генерации php-генерации страницы, т.е. запуска асинхронной операции) https://github.com/jmullee/PhpIPCMessageQueue
Ответ 14
Вы можете проверить PM2 здесь, http://pm2.keymetrics.io/
создайте ssh файл, такой как worker.sh, поместите в свой php-скрипт, с которым вы будете иметь дело.
worker.sh
php /path/myscript.php
начало демона
pm2 start worker.sh
Ура, вот и все.