Отказ от ответственности
Во-первых, я знаю, что этот вопрос (или его близкие варианты) задавали тысячу раз. Я действительно провел несколько часов в поисках очевидных и не очень очевидных мест, но может быть что-то маленькое, что я упускаю.
Контекст
Позвольте мне более четко определить проблему: я пишу приложение для рассылки новостей, в котором я хочу, чтобы фактический процесс отправки был асинхронным. Например, пользователь нажимает «отправить», запрос немедленно возвращается, а затем он может проверить ход выполнения на определенной странице (например, с помощью AJAX). Он написан в вашем традиционном стеке LAMP.
В конкретном хосте, который я использую, функции PHP exec() и system() отключены по соображениям безопасности, а системные функции Perl (exec, system и обратные кавычки) — нет. Таким образом, мое обходное решение заключалось в создании сценария «триггера» на Perl, который вызывает фактического отправителя через интерфейс командной строки PHP и перенаправляет на страницу прогресса.
Где я застрял
Сама строка, по которой звонит отправитель, на данный момент:
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";