Запуск задания в фоновом режиме из Perl БЕЗ ожидания возврата - PullRequest
9 голосов
/ 15 апреля 2010

Отказ от ответственности

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

Контекст

Позвольте мне более четко определить проблему: я пишу приложение для рассылки новостей, в котором я хочу, чтобы фактический процесс отправки был асинхронным. Например, пользователь нажимает кнопку «отправить», запрос немедленно возвращается, и затем он может проверить ход выполнения на определенной странице (например, через AJAX). Это написано в вашем традиционном стеке LAMP.

В конкретном хосте, который я использую, PHP exec () и system () отключены по соображениям безопасности, а системные функции Perl (exec, system и backticks) - нет. Поэтому мое решение обходного пути заключалось в создании сценария «триггера» в Perl, который вызывает фактического отправителя через PHP CLI и перенаправляет на страницу прогресса.

Где я застрял

Самая строка звонков отправителю, на данный момент:

system("php -q sender.php &");

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

Что я уже пробовал

  • Функция Perl exec () - тот же результат, что и для system ().
  • Изменив команду на: "php -q sender.php | at now"), надеясь, что демон "at" вернется и что сам процесс PHP не будет присоединен к Perl.
  • Выполнение команды 'косвенно': "/ bin / sh -c 'php -q sender.php &'" - все еще ожидает окончания отправки sender.php.
  • fork (), выполняющий процесс и выполняющий системный вызов в дочернем процессе (возможно, отключенный процесс) - тот же результат, что и выше

Моя тестовая среда

Просто чтобы быть уверенным, что я не пропускаю ничего очевидного, я создал скрипт sleeper.php, который просто спит пять секунд перед выходом. И скрипт test.cgi, который выглядит так, дословно:

#!/usr/local/bin/perl
system("php sleeper.php &");
print "Content-type: text/html\n\ndone";

Что мне теперь попробовать?

Ответы [ 5 ]

9 голосов
/ 15 апреля 2010

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

Это легко сделать с помощью модуля CPAN Proc :: Daemon :

use Proc::Daemon;
# do everything you need to do before forking the child...

# make into daemon; closes all open fds
Proc::Daemon::Init();
7 голосов
/ 01 июня 2010

Иногда STDERR и STDOUT также могут блокировать систему ... Чтобы получить оба, я использую (для большинства оболочек (bash, csh и т. Д.), Которые я использую ...):

system("php sender.php > /dev/null 2>&1 &");
6 голосов
/ 15 апреля 2010

Используйте fork() и затем вызывайте system в дочернем процессе.

my $pid = fork();
if (defined $pid && $pid == 0) {
    # child
    system($command);    # or exec($command)
    exit 0;
}
# parent
# ... continue ...
1 голос
/ 16 апреля 2010

Другой вариант - настроить сервер gearman и рабочий процесс (или процессы), которые отправляют электронную почту. Таким образом, вы контролируете, сколько электронной почты происходит одновременно, и нет необходимости в разветвлении. Клиент (ваша программа) может добавить задачу на сервер Gearman (в фоновом режиме, не ожидая результата, если это необходимо), и задания ставятся в очередь, пока сервер не передаст задание доступному работнику. Для gearman есть Perl и php API, так что это очень удобно.

0 голосов
/ 15 апреля 2010

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

system("php sender.php > /dev/null &");

Спасибо всем за помощь. Фактически, во время чтения всей истории о «демонизации» процесса у меня появилась идея отключить стандартный вывод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...