Запустить php-скрипт как процесс демона

Мне нужно запустить php-скрипт как процесс демона (дождаться инструкций и сделать что-нибудь). Работа cron не будет делать это для меня, потому что действия должны быть приняты, как только придет инструкция. Я знаю, что PHP не самый лучший вариант для процессов-демонов из-за проблем с управлением памятью, но по разным причинам я должен использовать PHP в этом случае. Я наткнулся на инструмент libslack под названием Daemon ( http://libslack.org/daemon ), он помогает мне управлять процессами демона, но за последние 5 лет обновлений не было, поэтому мне интересно, знаете ли вы некоторые другие альтернативы, подходящие для моего случая. Любая информация будет действительно оценена.

Вы можете запустить свой php-скрипт из командной строки (например, bash), используя

nohup php myscript.php &

& помещает ваш процесс в фоновом режиме.

Редактировать:
Да, есть некоторые недостатки, но невозможно контролировать? Это просто неправильно.
Простой kill processid остановит его. И это все еще самое лучшее и простое решение.

Другой вариант – использовать Upstart . Он был первоначально разработан для Ubuntu (и поставляется с ним по умолчанию), но предназначен для всех дистрибутивов Linux.

Этот подход похож на Supervisord и daemontools , поскольку он автоматически запускает демона при загрузке системы и респаунах при завершении скрипта.

Как настроить:

Создайте новый файл сценария в /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 script 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 

благодаря

Большое спасибо Кевину ван Зонневельду , откуда я узнал эту технику.

Если вы можете – возьмите копию расширенного программирования в среде UNIX . Вся глава 13 посвящена программированию демона. Примеры находятся в C, но для всей функции вам нужны обертки в PHP (в основном расширения pcntl и posix ).

В нескольких словах – написание демона (это возможно только для OS-es на основе nix – Windows использует службы) выглядит так:

  1. Вызовите umask(0) чтобы предотвратить проблемы с разрешением.
  2. fork() и иметь родительский выход.
  3. Вызовите setsid() .
  4. Настройка сигнала обработки SIGHUP (обычно это игнорируется или используется для сигнализации демона, чтобы перезагрузить его конфигурацию) и SIGTERM (чтобы заставить процесс выйти изящно).
  5. fork() и родительский выход.
  6. Измените текущий рабочий каталог с помощью chdir() .
  7. fclose() stdin , stdout и stderr и не пишите им. Правильный способ – перенаправить их на /dev/null или файл, но я не смог найти способ сделать это на PHP. Это возможно при запуске демона, чтобы перенаправить их с помощью оболочки (вам нужно будет выяснить, как это сделать, я не знаю :).
  8. Делай свою работу!

Кроме того, поскольку вы используете PHP, будьте осторожны с циклическими ссылками, поскольку сборщик мусора PHP до PHP 5.3 не может собирать эти ссылки, и процесс будет протекать в памяти, пока он в конечном итоге не сработает.

Я запускаю большое количество PHP-демонов.

Я согласен с вами в том, что PHP не лучший (или даже хороший) язык для этого, но демоны используют код с компонентами, ориентированными на веб-интерфейс, поэтому в целом это хорошее решение для нас.

Для этого мы используем daemontools. Это умный, чистый и надежный. Фактически мы используем его для запуска всех наших демонов.

Вы можете проверить это на http://cr.yp.to/daemontools.html .

EDIT: быстрый список функций.

  • Автоматически запускает демон при перезагрузке
  • Автоматически перезапускать dameon при сбое
  • Ведение журнала выполняется для вас, включая опрокидывание и обрезку
  • Интерфейс управления: 'svc' и 'svstat'
  • UNIX-friendly (не плюс для всех)

Ты можешь

  1. Используйте nohup как предложил Хенрик.
  2. Используйте screen и запускайте свою PHP-программу как обычный процесс внутри этого. Это дает вам больше контроля, чем использование nohup .
  3. Используйте демонайзер, такой как http://supervisord.org/ (он написан на Python, но может демонтировать любую программу командной строки и дать вам удаленный элемент управления для управления им).
  4. Напишите свою собственную обертку демона, как предположил Эмиль, но это чрезмерное ИМО.

Я бы рекомендовал простейший метод (экран, на мой взгляд), а затем, если вы хотите больше функций или функций, переходите к более сложным методам.

С помощью нового systemd вы можете создать сервис (на основе rhel linux).

Вы должны создать файл в /etc/systemd/system/ , например. myphpdaemon.service и разместите контент, подобный этому, myphpdaemon будет именем сервиса:

 [Unit] Description=Your PHP Daemon Service #Requires=mysqld.service memcached.service #May your script needs mysql or other services to run. #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 #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 #Restart=on-failure #RestartPreventExitStatus=1 #PrivateTmp=false 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=process Restart=on-failure RestartSec=42s [Install] WantedBy=default.target 

Примечание. Каждый раз, когда вы меняете свой «myphpdaemon.service», вы должны запустить `systemctl daemon-reload ', но не беспокойтесь, если вы этого не сделаете, он будет запрашиваться, когда это необходимо.

Существует несколько способов решить эту проблему.

Я не знаю специфики, но, возможно, есть еще один способ вызвать процесс PHP. Например, если вам нужен код для запуска на основе событий в базе данных SQL, вы можете настроить триггер для выполнения сценария. Это действительно легко сделать в PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html .

Честно говоря, я считаю, что лучше всего создать процесс Дэймона, используя nohup. nohup позволяет команде продолжать выполнение даже после выхода пользователя из системы:

 nohup php myscript.php & 

Однако есть очень серьезная проблема. Как вы сказали, менеджер памяти PHP является полным мусором, он был построен с предположением, что скрипт выполняется всего несколько секунд, а затем существует. Ваш PHP-скрипт начнет использовать GIGABYTES памяти через несколько дней. Вы также должны создать сценарий cron, который запускается каждые 12 или, возможно, 24 часа, который убивает и повторно запускает ваш php-скрипт следующим образом:

 killall -3 php nohup php myscript.php & 

Но что, если сценарий был посреди работы? Убит 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-скрипт может открыть файл с fopen ("file", "w") ;. Только один процесс может иметь блокировку записи в файле, поэтому, используя это, вы можете убедиться, что работает только одна копия вашего PHP-скрипта.

Удачи!

Кевин ван Зонневельд написал очень хорошую подробную статью об этом , в своем примере он использует пакет System_Daemon PEAR (последняя дата выпуска в 2009-09-02).

Проверьте https://github.com/shaneharter/PHP-Daemon

Это объектно-ориентированная библиотека демона. Он имеет встроенную поддержку таких функций, как ведение журнала и восстановление ошибок, а также поддержка создания фоновых работников.

Недавно мне понадобилось кросс-платформенное решение (Windows, Mac и Linux) для проблемы запуска PHP-скриптов в качестве демонов. Я решил проблему, написав свое собственное решение на C ++ и создав двоичные файлы:

https://github.com/cubiclesoft/service-manager/

Полная поддержка Linux (через sysvinit), но также службы Windows NT и запуск Mac OSX.

Если вам просто нужна Linux, то пара других решений, представленных здесь, работает достаточно хорошо и, в зависимости от вкуса. В наши дни также есть Upstart и systemd, которые имеют резервные копии для скриптов sysvinit. Но половина смысла использования PHP заключается в том, что он носит кросс-платформенный характер, поэтому код, написанный на этом языке, имеет очень хорошие шансы работать везде как есть. Недостатки начинают появляться, когда некоторые внешние внешние аспекты уровня ОС входят в изображение, например, в системные службы, но вы получите эту проблему с большинством языков сценариев.

Попытка поймать сигналы, как кто-то здесь предложил в PHP userland, не является хорошей идеей. pcntl_signal() прочитайте документацию по pcntl_signal() и вы быстро узнаете, что PHP обрабатывает сигналы с использованием некоторых довольно неприятных методов (в частности, «тиков»), которые пережевывают кучу циклов для чего-то, что редко встречается процессами (то есть сигналами). Обработка сигналов в PHP также доступна только на платформах POSIX, а поддержка отличается от версии PHP. Первоначально это звучит как достойное решение, но оно не очень полезно.

С течением времени PHP также улучшал проблемы с утечкой памяти. Вы все еще должны быть осторожны (парсер DOM XML имеет тенденцию течь все еще), но я редко вижу процессы побега в эти дни, а трекер ошибок PHP довольно тихий по сравнению с днями ожидания.

Как уже упоминалось выше, запуск PHP в качестве демона довольно прост и может быть выполнен с использованием одной строки команды. Но актуальной проблемой является ее поддержание и управление им. Некоторое время назад у меня была та же проблема, и хотя есть много доступных решений, большинство из них имеют множество зависимостей или их трудно использовать и не подходят для основных применений. Я написал сценарий оболочки, который может управлять любым процессом / приложением, включая скрипты PHP cli. Он может быть установлен как cronjob для запуска приложения и будет содержать приложение и управлять им. Если он выполняется снова, например, через один и тот же cronjob, он проверяет, работает ли приложение или нет, если он делает это, то просто выходит и позволяет своему предыдущему экземпляру продолжить управление приложением.

Я загрузил его в github, не стесняйтесь использовать его: https://github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

Просто наблюдает за вашим приложением (запуск, перезапуск, журнал, мониторинг и т. Д.). общий скрипт, чтобы убедиться, что ваше приложение остается работоспособным. Преднамеренно он использует имя процесса instread для файла pid / lock, чтобы предотвратить все его побочные эффекты и сохранить сценарий как можно более простым и максимально возможным, поэтому он всегда работает, даже когда сам EasyDaemonizer перезапускается. Особенности

  • Запускает приложение и, возможно, настраиваемую задержку для каждого запуска
  • Уверен, что работает только один экземпляр
  • Контролирует использование ЦП и автоматически запускает приложение, когда оно достигает определенного порога
  • Настройка EasyDeamonizer для запуска через cron, чтобы запустить его снова, если он по какой-либо причине остановлен
  • Регистрирует свою деятельность

Я написал и развернул простой php-демон, код здесь онлайн

https://github.com/jmullee/PhpUnixDaemon

Особенности: снижение привилегий, обработка сигналов, ведение журнала

Я использовал его в обработчике очереди (прецедент: триггер длительной операции с веб-страницы, без необходимости генерации php-генерации страницы, т.е. запуск асинхронной операции) https://github.com/jmullee/PhpIPCMessageQueue