Создание демона на PHP или скрипты, которые работают сами по себе
При разработке веб-приложений может возникнуть потребность в том, чтобы сервер что-то делал самостоятельно, без участия пользователя: занимался постобработкой данных, делал рассылки, отслеживал что-то, обрабатывал. Когда речь заходит о самостоятельной работе сервера, первое, что приходит в голову вебмастеру, привыкшему работать c Unix-подобными серверами, это программа Cron, которая может выполнять команды по расписанию. Но как быть, если не существует никакого расписания, и какой-то скрипт должен быть запущен постоянно и работать сам по себе, запускаясь заново сразу после своего выполнения? Вдохновлённый разработкой сервиса CheckTrust, вообразив себя Некромантом, я решил поделиться своим опытом в создании таких скриптов-демонов на PHP.
Сразу оговорюсь, что всё, о чём будет идти речь в этой статье, применимо лишь для Unix-подобных операционных систем, и не будет работать под Windows. Речь идёт именно об альтернативе крону. Несчастным любителям Windows придётся колдовать с "Планировщиком заданий" - Чёрная Магия останется недоступна для них :) Кроме того, потребуется ssh доступ, а в идеале - доступ php скриптов к командной строке.
Что есть программа-демон и как написать демона на PHP
Применимо к PHP, это скрипт, который может работать самостоятельно, без остановок и без участия пользователя. Как получить такой скрипт? На самом деле, очень просто, нужно лишь нарушить одно из первых правил программирования, которому учат в школе, и создать бесконечный цикл:
Простой до невозможности код вызывает, всё же, несколько вопросов. Как его запустить? Как отслеживать его выполнение? Как его остановить?
Как запустить php-демона
А как вообще запускают php-скрипты? Если это веб-приложение, то при помощи браузера и веб-сервера. Но этот вариант не подходит, ведь мы имеем дело с бесконечным скриптом, а время выполнения скриптов ограничены директивой max_execution_time в php.ini. Следовательно, бесконечный скрипт необходимо запускать через консоль, ведь тогда максимальное время его выполнения не учитывается. Примерно так выглядит команда запуска демона:
Для ручного запуска её нужно ввести в ssh терминале (putty, WinSCP и т.д.), а для запуска системой при загрузке - в соответствующий файл автозагрузки (положение и название файла зависит от операционной системы). Обратите внимание, что консольный скрипт демона запускается в фоновом режиме, не вовлекая пользователя в ожидание его завершения (ведь скрипт бесконечен). Именно в наличии возможности запустить процесс в фоновом режиме и лежит причина того, что описываемый мной способ не подходит для Windows-серверов. После запуска в консоли должен отобразиться идентификатор процесса нашего демона, так называемый PID.
Отслеживание и остановка демонов
Проверить, запущен ли процесс демона можно просто открыв список процессов в системе:
Найти демона в списке процессов несложно, как по команде запуска, так и по PID:
Остановить процесс демона можно так же, как и любой другой процесс:
В приведённом примере xxxx - это и есть PID, идентификатор процесса.
Стоит отметить, что это не остановка, а именно "убийство" процесса демона. Дело в том, что работа скрипта будет прервана где попало, что не всегда и не всем подходит. По идее, в таком случае демона нужно останавливать где-то между его итерациями и уже не из консоли. К примеру, мы можем создать в базе данных или в каком-то файле на сервере заявку на остановку скрипта, а между итерациями демона проверять, нет ли такой заявки. Если заявка будет обнаружена, остановить цикл оператором break.
Система управления демонами
А что, если требуется создать и отслеживать сразу много демонов? К примеру, в упомянутом выше сервисе CheckTrust обработкой данных и проектов пользователей занимаются > 30 таких скриптов. Создавать и следить за ними из консоли очень неудобно - нужен более дружественный интерфейс.
Круто, да? :) Как раз для создания подобной системы было бы неплохо иметь доступ к командной строке из php. Каждый демон - запись в базе данных, напротив которой можно проставить команду его запуска, а так же PID процесса. Следовательно, появляется возможность запускать, останавливать и отслеживать статус демонов прямо из веб-интерфейса. В итоге сами демоны у меня получились частью консольного приложения, а система управления ими - частью веб-приложения.
Поскольку система, показанная выше, заточена строго под CheckTrust, её код показывать я не буду. Зато скопирую сюда код php класса для управления процессами, который я использовал при её создании:
Единственный недостаток этого класса - то, что я уже описывал ваше - он останавливает процессы методом kill, но мне пока что этого достаточно :) А вот и пример его использования:
Подводя итог, хочу сказать, что это не единственно возможная и, вполне возможно, не самая оптимальная реализация демонов на php. К примеру, для многопроцессовых демонов существует крутое расширение PHP PCNTL. Кто-то, возможно, даже скажет, что для консольных приложений существуют совсем другие языки программирования. Но, как ни крути, у данной реализации есть неоспоримые преимущества:
- Она простая, как тапок. Демон - это просто бесконечный цикл, куда уж проще.
- Она совместима с веб-приложениями - являясь частью веб-сервиса, мои демоны опираются на существующие наработки, используют те же модели данных, классы и методы работы с ними.
- Она работает! Серьёзно - некоторые демоны у нас запущены уже несколько месяцев и, будучи грамотно написанными, не тупят, не зависают, не поглощают память.
Спасибо за внимание :) Если у кого-нибудь возникнут вопросы или идеи, с удовольствием отвечу на них в комментариях.