Я работаю над довольно большим веб-приложением, а бэкэнд в основном на PHP. В коде есть несколько мест, где мне нужно выполнить какую-то задачу, но я не хочу заставлять пользователя ждать результата. Например, при создании новой учетной записи мне нужно отправить им приветственное письмо. Но когда они нажимают кнопку «Завершить регистрацию», я не хочу заставлять их ждать, пока письмо действительно не будет отправлено, я просто хочу начать процесс и сразу же вернуть сообщение пользователю.
До сих пор в некоторых местах я использовал хак с exec (). В основном делать такие вещи, как:
exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");
Который, кажется, работает, но мне интересно, есть ли лучший способ. Я рассматриваю возможность написания системы, которая ставит задачи в очередь в таблице MySQL, и отдельного долгосрочного сценария PHP, который запрашивает эту таблицу раз в секунду и выполняет любые новые задачи, которые он находит. Это также имело бы преимущество, позволяя мне распределить задачи между несколькими рабочими машинами в будущем, если бы мне это было нужно.
Я заново изобретаю колесо? Есть ли лучшее решение, чем взлом exec () или очередь MySQL?
Если вы просто хотите выполнить один или несколько HTTP-запросов, не ожидая ответа, также существует простое решение PHP.
В вызывающем скрипте:
В вызываемом script.php вы можете вызывать эти функции PHP в первых строках:
Это приводит к тому, что сценарий продолжает работать без ограничения по времени, когда соединение HTTP закрыто.
источник
Другой способ ветвления процессов - через curl. Вы можете настроить свои внутренние задачи как веб-сервис. Например:
Затем в ваших пользовательских скриптах заходите в сервис:
Ваш сервис может отслеживать очередь задач с помощью mysql или чего-то еще, что вам нравится: суть в том, что все в сервисе, а ваш скрипт просто использует URL-адреса. Это освобождает вас от необходимости переместить службу на другой компьютер / сервер, если это необходимо (т.е. легко масштабируется).
Добавление http-авторизации или пользовательской схемы авторизации (например, веб-сервисов Amazon) позволяет вам открывать ваши задачи для использования другими людьми / сервисами (если вы хотите), и вы можете пойти дальше и добавить службу мониторинга сверху, чтобы отслеживать состояние очереди и задачи.
Требуется немного работы по настройке, но есть много преимуществ.
источник
Я использовал Beanstalkd для одного проекта и планировал снова. Я обнаружил, что это отличный способ запуска асинхронных процессов.
Несколько вещей, которые я сделал с этим:
Я написал систему на основе Zend-Framework для декодирования «симпатичного» URL, например, для изменения размера изображения, которое оно будет вызывать
QueueTask('/image/resize/filename/example.jpg')
. Сначала URL был декодирован в массив (модуль, контроллер, действие, параметры), а затем преобразован в JSON для внедрения в саму очередь.Затем долго работающий сценарий cli извлекает задание из очереди, запускает его (через Zend_Router_Simple) и, при необходимости, помещает информацию в memcached для того, чтобы PHP веб-сайта мог подобрать ее по мере необходимости.
Еще одна проблема, которую я также добавил, заключалась в том, что перед повторным запуском cli-скрипт работал только 50 циклов, но если он действительно хотел перезапустить, как запланировано, он сделал бы это немедленно (будучи запущенным через bash-скрипт). Если возникла проблема, и я это сделал
exit(0)
(значение по умолчанию дляexit;
илиdie();
), он сначала приостановился бы на пару секунд.источник
Если это просто вопрос обеспечения дорогостоящих задач, в случае поддержки php-fpm, почему бы не использовать
fastcgi_finish_request()
функцию?Вы действительно не используете асинхронность таким образом:
fastcgi_finish_request()
.Еще раз php-fpm нужен.
источник
Вот простой класс, который я написал для своего веб-приложения. Это позволяет разветвлять PHP-скрипты и другие скрипты. Работает на UNIX и Windows.
источник
Это тот же метод, которым я пользуюсь уже пару лет, и я не видел и не нашел ничего лучшего. Как говорили люди, PHP является однопоточным, так что вы ничего не можете сделать.
Я фактически добавил один дополнительный уровень к этому, и это получает и хранит идентификатор процесса. Это позволяет мне перенаправить на другую страницу и позволить пользователю сидеть на этой странице, используя AJAX, чтобы проверить, завершен ли процесс (идентификатор процесса больше не существует). Это полезно в тех случаях, когда длина скрипта может привести к превышению времени ожидания браузера, но пользователь должен дождаться завершения этого скрипта перед следующим шагом. (В моем случае это были большие ZIP-файлы с CSV-подобными файлами, которые добавляют в базу данных до 30 000 записей, после чего пользователь должен подтвердить некоторую информацию.)
Я также использовал аналогичный процесс для генерации отчетов. Я не уверен, что использовал бы «фоновую обработку» для чего-то такого, как электронная почта, если только нет реальной проблемы с медленным SMTP. Вместо этого я мог бы использовать таблицу в качестве очереди, а затем иметь процесс, который запускается каждую минуту для отправки электронных писем в очереди. Вы должны быть осторожны при отправке электронных писем дважды или других подобных проблем. Я бы рассмотрел аналогичный процесс организации очередей и для других задач.
источник
PHP HAS многопоточность, его просто не включен по умолчанию, есть расширение называется Pthreads , который делает именно это. Вам понадобится php, скомпилированный с ZTS. (Thread Safe) Ссылки:
Примеры
Еще один учебник
Pthreads PECL Extension
источник
Это отличная идея использовать cURL, как предложено rojoca.
Вот пример. Вы можете отслеживать text.txt, пока скрипт работает в фоновом режиме:
источник
К сожалению, PHP не имеет каких-либо собственных возможностей потоков. Так что я думаю, что в этом случае у вас нет выбора, кроме как использовать какой-то специальный код, чтобы делать то, что вы хотите.
Если вы будете искать в сети потоки PHP, некоторые люди придумали способы имитации потоков на PHP.
источник
Если вы задали HTTP-заголовок Content-Length в ответе «Спасибо за регистрацию», то браузер должен закрыть соединение после получения указанного количества байтов. Это оставляет процесс на стороне сервера запущенным (при условии, что установлен ignore_user_abort), поэтому он может завершить работу, не заставляя конечного пользователя ждать.
Конечно, вам нужно будет вычислить размер содержимого вашего ответа перед рендерингом заголовков, но это довольно просто для коротких ответов (запись вывода в строку, вызов strlen (), вызов заголовка (), отображение строки).
Такой подход имеет преимущество , не заставляя вас управлять «передний конец» очереди, и , хотя вы , возможно , придется сделать некоторую работу на конце задней для предотвращения гонки HTTP дочерние процессы наступали друг на друга, это то , что вам нужно сделать уже , тем не мение.
источник
header('Content-Length: 3'); echo '1234'; sleep(5);
то, хотя браузер берет только 3 символа, он все еще ждет в течение 5 секунд, прежде чем показать ответ. Чего мне не хватает?phpinfo()
. Единственное, что я могу себе представить, это то, что мне нужно сначала достичь минимального размера буфера, например, 256 или около того байтов.Если вам не нужен полноценный ActiveMQ, я рекомендую рассмотреть RabbitMQ . RabbitMQ - это легкая система обмена сообщениями, использующая стандарт AMQP .
Я также рекомендую обратиться к php-amqplib - популярной клиентской библиотеке AMQP для доступа к брокерам сообщений на основе AMQP.
источник
я думаю, вам стоит попробовать эту технику, это поможет вызвать столько страниц, сколько вам нужно, все страницы будут работать одновременно независимо, не дожидаясь ответа каждой страницы как асинхронного.
cornjobpage.php // главная страница
testpage.php
PS: если вы хотите отправить параметры URL как цикл, следуйте этому ответу: https://stackoverflow.com/a/41225209/6295712
источник
Создание новых процессов на сервере с использованием
exec()
или непосредственно на другом сервере с использованием curl вовсе не так хорошо масштабируется, если мы стремимся к exec, вы в основном заполняете свой сервер долгосрочными процессами, которые могут обрабатываться другими серверами, не подключенными к сети, и использование curl связывает другой сервер, если вы не встроите балансировку нагрузки.Я использовал Gearman в нескольких ситуациях, и я считаю, что он лучше подходит для такого случая использования. Я могу использовать один сервер очереди заданий, чтобы в основном обрабатывать очереди всех заданий, которые должен выполнять сервер, и ускорять рабочие серверы, каждый из которых может запускать столько экземпляров рабочего процесса, сколько необходимо, и увеличивать количество рабочие серверы по мере необходимости и раскрутить их, когда не нужно. Это также позволило мне полностью отключить рабочие процессы, когда это необходимо, и поставить их в очередь, пока рабочие не вернутся в оперативный режим.
источник
PHP является однопоточным языком, поэтому нет никакого официального способа запустить асинхронный процесс с ним, кроме использования
exec
илиpopen
. Существует сообщение в блоге о том, что здесь . Ваша идея для очереди в MySQL также хорошая идея.Ваше конкретное требование здесь для отправки электронной почты пользователю. Мне любопытно, почему вы пытаетесь сделать это асинхронно, поскольку отправка электронного письма - довольно тривиальная и быстрая задача. Я полагаю, если вы отправляете тонны электронной почты, а ваш интернет-провайдер блокирует вас по подозрению в рассылке спама, это может быть одной из причин для постановки в очередь, но кроме этого я не могу придумать ни одной причины сделать это таким образом.
источник