В первую очередь, я знаю, что этот вопрос (или близкие изменения) задали тысячу раз. Я действительно провел несколько часов, смотря в очевидном и местах not-so-obvious, но может быть что-то маленькое, которое я пропускаю.
Позвольте мне определить проблему более ясно: я пишу приложение новостной рассылки, в котором я хочу, чтобы фактический процесс отправки был асинхронен. Как в, пользовательские щелчки "отправляют", возвраты запроса сразу, и затем они могут проверить прогресс определенной страницы (через Ajax, например). Это записано в Вашем традиционном стеке LAMP.
В конкретном хосте я использую, должностное лицо PHP () и система () отключено из соображений безопасности, но системные функции Perl (должностное лицо, система и обратные галочки) не. Таким образом, мое обходное решение состояло в том, чтобы создать "триггерный" сценарий в Perl, который называет фактического отправителя через CLI PHP и перенаправляет к странице прогресса.
Очень выравнивают вызовы, которые отправитель на данный момент:
system("php -q sender.php &");
Проблема быть, это не возвращается сразу, но ожидает сценария для окончания. Я хочу, чтобы это работало в фоновом режиме и имело сам системный вызов, возвращаются сразу же. Я также пытался запустить подобный скрипт в своем терминале Linux, и на самом деле подсказка не показывает, пока сценарий не закончился, даже при том, что мой тестовый вывод не работает, указывая, что это действительно работает в фоновом режиме.
Только, чтобы быть уверенным, что я не пропускаю ничего очевидного, я создал sleeper.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();
Другой вариант - настроить сервер gearman и рабочий процесс (или процессы), которые отправляют электронную почту. Таким образом, вы контролируете, сколько электронных писем происходит одновременно, и никакого разветвления не требуется. Клиент (ваша программа) может добавить задачу на сервер gearman (в фоновом режиме, не дожидаясь результата при желании), и задания ставятся в очередь до тех пор, пока сервер не передаст задание доступному исполнителю. Для gearman есть API-интерфейсы perl и php, так что это очень удобно.
Проблему удалось решить.По-видимому, то, что удерживало его от возврата, было то, что вызов отправителя таким образом не отключал стандартный вывод. Итак, решением было просто изменить системный вызов на:
system("php sender.php > /dev/null &");
Спасибо всем за помощь. Фактически, когда я читал всю историю о «демонизации» процесса, мне пришла в голову идея отключить stdout.
Используйте fork ()
, а затем вызовите систему
в дочернем процессе.
my $pid = fork();
if (defined $pid && $pid == 0) {
# child
system($command); # or exec($command)
exit 0;
}
# parent
# ... continue ...
Иногда STDERR и STDOUT также могут блокировать систему... Чтобы получить и то, и другое, я использую (для большинства сред оболочки (bash, csh и т.д.), которые я использую...):
system("php sender.php > /dev/null 2>&1 &");