Прежде всего, я знаю, что этот вопрос (или близкие варианты) задавался тысячу раз. Я действительно потратил несколько часов, глядя в очевидные и не столь очевидные места, но может быть что-то маленькое, что мне не хватает.
Позвольте мне более четко определить проблему: я пишу приложение для рассылки новостей, в котором хочу, чтобы фактический процесс отправки был асинхронным. Как и в случае, пользователь нажимает «отправить», немедленно запрашивает возврат, а затем проверяет прогресс на определенной странице (например, через AJAX). Он написан в вашем традиционном стеке LAMP.
В конкретном хосте, который я использую, PHP exec () и system () отключены по соображениям безопасности, но системные функции Perl (exec, system и backticks) – нет. Так что мой обходной путь решение заключалось в создании сценария «триггера» в Perl, который вызывает фактического отправителя через CLI PHP и перенаправляется на страницу прогресса.
Сама строка, вызывающая отправителя, на данный момент:
system("php -q sender.php &");
Проблема заключается в том, что она не сразу возвращается, но ждет завершения скрипта. Я хочу, чтобы он работал в фоновом режиме и сразу же возвращался к системному вызову. Я также попробовал запустить аналогичный скрипт в моем терминале Linux, и на самом деле приглашение не отображается до тех пор, пока скрипт не завершится, хотя мой тестовый результат не запускается, указывая, что он действительно работает в фоновом режиме.
Чтобы быть уверенным, что я ничего не теряю, я создал скрипт sleepper.php, который просто спит пять секунд до выхода. И скрипт test.cgi, похожий на это, дословно:
#!/usr/local/bin/perl system("php sleeper.php &"); print "Content-type: text/html\n\ndone";
По сути вам нужно «демонировать» процесс – разблокировать дочерний элемент, а затем полностью отключить его от родителя, чтобы родитель мог безопасно завершить работу, не затрагивая ребенка.
Вы можете сделать это легко с помощью модуля 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();
Иногда STDERR и STDOUT также могут блокировать систему … Для получения обоих я использую (для большинства оболочек (bash, csh и т. Д.), Которые я использую …):
system("php sender.php > /dev/null 2>&1 &");
Используйте fork()
а затем вызовите system
в дочернем процессе.
my $pid = fork(); if (defined $pid && $pid == 0) { # child system($command); # or exec($command) exit 0; } # parent # ... continue ...
Другой вариант – настроить сервер ретранслятора и рабочий процесс (или процессы), которые выполняют электронную почту. Таким образом, вы контролируете, сколько электронной почты идет одновременно, и не требуется разветвление. Клиент (ваша программа) может добавить задачу на сервер ретранслятора (в фоновом режиме, не ожидая результата, если это необходимо), а задания помещаются в очередь до тех пор, пока сервер не передаст задание доступному рабочему. Есть API perl и php для gearman, так что это очень удобно.
Удалось решить проблему. Видимо, что удерживало его от возвращения, заключалось в том, что вызов отправителя таким образом не отключил выступление. Таким образом, решение просто меняло системный вызов на:
system("php sender.php > /dev/null &");
Спасибо всем за помощь. Фактически, при чтении всей истории о «демонализации» процесса у меня возникла идея отключить стандартный вывод.