Запускать задачу PHP асинхронно - PullRequest
135 голосов
/ 13 мая 2009

Я работаю над довольно большим веб-приложением, а бэкэнд в основном на PHP. В коде есть несколько мест, где мне нужно выполнить какую-то задачу, но я не хочу заставлять пользователя ждать результата. Например, при создании новой учетной записи мне нужно отправить им приветственное письмо. Но когда они нажимают кнопку «Завершить регистрацию», я не хочу заставлять их ждать, пока письмо действительно не будет отправлено, я просто хочу начать процесс и сразу же вернуть сообщение пользователю.

До сих пор в некоторых местах я использовал то, что похоже на хак с exec (). В основном делают такие вещи, как:

exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");

Что, кажется, работает, но мне интересно, есть ли лучший способ. Я рассматриваю возможность написания системы, которая ставит задачи в очередь в таблице MySQL, и отдельного долгосрочного скрипта PHP, который запрашивает эту таблицу раз в секунду и выполняет любые новые задачи, которые он находит. Это также позволило бы мне распределить задачи между несколькими рабочими машинами в будущем, если бы мне это понадобилось.

Я заново изобретаю колесо? Есть ли лучшее решение, чем взлом exec () или очередь MySQL?

Ответы [ 15 ]

1 голос
/ 06 августа 2011

Если вы задали HTTP-заголовок Content-Length в ответе «Спасибо за регистрацию», браузер должен закрыть соединение после получения указанного количества байтов. Это оставляет процесс на стороне сервера запущенным (при условии, что установлен ignore_user_abort), поэтому он может завершить работу, не заставляя конечного пользователя ждать.

Конечно, вам нужно будет вычислить размер содержимого вашего ответа перед рендерингом заголовков, но это довольно просто для коротких ответов (запись выходных данных в строку, вызов strlen (), вызов заголовка (), отображение строки).

Преимущество этого подхода в том, что , а не , заставляет вас управлять очередью "переднего плана", и, хотя вам может потребоваться проделать некоторую работу во внутреннем интерфейсе, чтобы не допустить наступления дочерних процессов HTTP на каждом Во-вторых, это то, что вам нужно было сделать, в любом случае.

1 голос
/ 13 мая 2009

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

Если вы будете искать в сети потоки PHP, некоторые люди придумают способы имитации потоков на PHP.

0 голосов
/ 31 декабря 2017

Создание новых процессов на сервере с использованием exec() или непосредственно на другом сервере с использованием curl вовсе не так хорошо масштабируется, если мы стремимся к exec, вы в основном заполняете свой сервер длительными процессами, которые могут быть обработаны другие серверы, не связанные с веб-интерфейсом, и использование свертывания связывает другой сервер, если вы не встроите какое-либо распределение нагрузки.

Я использовал Gearman в нескольких ситуациях, и я нахожу его лучше для такого случая использования. Я могу использовать один сервер очереди заданий, чтобы в основном обрабатывать очереди всех заданий, которые должен выполнять сервер, и ускорять рабочие серверы, каждый из которых может запускать столько экземпляров рабочего процесса, сколько необходимо, и увеличивать количество рабочие серверы по мере необходимости и раскрутить их, когда не нужно. Это также позволяет мне полностью выключать рабочие процессы, когда это необходимо, и ставить их в очередь до тех пор, пока рабочие не вернутся в оперативный режим.

0 голосов
/ 19 декабря 2016

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

cornjobpage.php // главная страница

    <?php

post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue");
//post_async("http://localhost/projectname/testpage.php", "Keywordname=testValue2");
//post_async("http://localhost/projectname/otherpage.php", "Keywordname=anyValue");
//call as many as pages you like all pages will run at once independently without waiting for each page response as asynchronous.
            ?>
            <?php

            /*
             * Executes a PHP page asynchronously so the current page does not have to wait for it to     finish running.
             *  
             */
            function post_async($url,$params)
            {

                $post_string = $params;

                $parts=parse_url($url);

                $fp = fsockopen($parts['host'],
                    isset($parts['port'])?$parts['port']:80,
                    $errno, $errstr, 30);

                $out = "GET ".$parts['path']."?$post_string"." HTTP/1.1\r\n";//you can use POST instead of GET if you like
                $out.= "Host: ".$parts['host']."\r\n";
                $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
                $out.= "Content-Length: ".strlen($post_string)."\r\n";
                $out.= "Connection: Close\r\n\r\n";
                fwrite($fp, $out);
                fclose($fp);
            }
            ?>

testpage.php

    <?
    echo $_REQUEST["Keywordname"];//case1 Output > testValue
    ?>

PS: если вы хотите отправить параметры URL как цикл, следуйте этому ответу: https://stackoverflow.com/a/41225209/6295712

0 голосов
/ 13 мая 2009

PHP является однопоточным языком, поэтому нет официального способа запустить с ним асинхронный процесс, кроме использования exec или popen. Об этом есть запись в блоге . Ваша идея для очереди в MySQL также является хорошей идеей.

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

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