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

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

12 ответов


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

nohup php myscript.php &

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

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


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

этот подход похож на Supervisord и сайтов, в том, что он автоматически запускает демон при загрузке системы и возрождается по завершении сценария.

как настроить его:

создать новый файл скрипта /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 расширения).

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

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

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


новые systemd в вы можете создать службу (на основе rhel linux).

вы должны создать файл или ссылка на /etc/systemd/system/, например. мифпдемон.сервис и разместить такой контент, как этот, 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's 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 должен выполняться один раз в цикле (например, diggest), вы можете использовать сценарий оболочки или bash для вызова в файл службы systemd вместо PHP напрямую, например:

#!/usr/bin/env bash
script_path="/app/services/"

while [ : ]
do
#    clear
    php -f "$script_path"".php" fixedparameter   > /dev/null 2>/dev/null
    sleep 1
done

если вы выбрали эту опцию, вы должны изменить KillMode to mixed для процессов, bash(main) и php(child) будут убиты.

ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
KillMode=process

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


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

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

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

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

ИЗМЕНИТЬ: A краткий список функций.

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

вы можете

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

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


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

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

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

nohup php myscript.php &

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

killall -3 php
nohup php myscript.php &

но что, если сценарий был в середине работы? Ну, убить -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');

идея $lock заключается в том, что php-скрипт может открыть файл с помощью fopen ("file","w");. Только один процесс может иметь блокировку записи в файле, поэтому с помощью этого вы можете убедиться, что работает только одна копия вашего PHP-скрипта.

Удачи!


Кевин ван Зонневельд написал очень хорошую подробную статью об этом в своем примере он использует System_Daemon груша пакет (дата последнего выпуска 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 launchd.

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

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

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


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

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

EasyDeamonizer

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

  • запускает приложение и, возможно, настроенную задержку для каждого запуска
  • гарантирует, что только один экземпляр работает
  • контролирует использование процессора и автоматически перезапускает приложение, когда оно достигает определенного порога
  • установка EasyDeamonizer для запуска через cron, чтобы запустить его снова, если он остановлен по какой-либо причине
  • регистрирует свою активность

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

https://github.com/jmullee/PhpUnixDaemon

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

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