Всем привет. Столкнулся с такой проблемой, что при выполнение php скрипта (скрипт больше минуты выполняется) сервер намертво зависает и обратиться к нему у с клиента, который запустил скрипт нельзя, пока скрипт не завершит свою работу. Скрипт запускается по средствам нажатия пользователем кнопки (Ajax). Как мне сделать так, чтобы сервер продолжал выполнять скрипт в фоновом режиме и не зависал для клиента? Я рассматривал вариант Pthreads, но еще не пробовал, не знаю, имеет ли это смысл.
Обновление #1
Начал копать в сторону PHP-FPM, но нужно разбираться в настройке, решил отложить на будущее, решение достаточно хорошее и мне понравилось. Время у меня поджимает, нашел в интернете функцию:
function exec_script($url, $params = array())
{
$parts = parse_url($url);
if (!$fp = fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80))
{
return false;
}
$data = http_build_query($params, '', '&');
fwrite($fp, "POST " . (!empty($parts['path']) ? $parts['path'] : '/') . " HTTP/1.1\r\n");
fwrite($fp, "Host: " . $parts['host'] . "\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: " . strlen($data) . "\r\n");
fwrite($fp, "Connection: Close\r\n\r\n");
fwrite($fp, $data);
fclose($fp);
return true;
}
exec_script('http://example.com/b.php', array('foo' => 'bar'));
Думаю создать класс AsyncExecutor или что-то в этом духе и использовать данный метод. Быстро и сердито, так сказать. Если есть более элегантное и лучшее решение - пишите, буду рад любой помощи.
Ну, стандартных решений несколько. Выбирать, какой лучше в конкретно вашем случае - исходя из совокупности факторов.
Клиент, кроме результата выполнения запроса, должен уметь принимать ответ вроде "еще не готово, ждите", и корректно реагировать на него (показывать анимацию, повторять запрос через Х секунд).
А вот как быть на стороне сервера - вариантов несколько:
pcntl_fork() - эта функция позволяет "раздвоить" процесс выполнения скрипта в некой точке, после чего один процесс должен отдать клиенту ответ "ждите", а второй - начать выполнять долгую операцию, предварительно избавившись от временного лимита - ste_time_limit(0), а также, установив некий флаг "процесс выполняется" (в текстовом файле на сервере, в БД, еще где-нибудь, где данные не теряются в конце выполнения скрипта). А по окончании выполнения - туда же сохранить результаты. При повторном запросе, скрипт должен сначала заглянуть в этот флаг "выполняется процесс". Если выполняется - сразу отдает "ждите", если не выполняется и результаты сохранены - отдать результаты. Если ни того ни другого - значит надо запускать процесс.
серверный скрипт (которого опрашивают ajax-ом) вообще не выполняет тяжелый запрос, а только записывает "задание для выполнения", и возвращает либо "ждите", либо "готово". А тяжелой работой занимается отдельный скрипт в фоне, который поднимается по крону, смотрит в БД, и если там есть задача - начинает ее выполнять (точно так же, в базе пометив "эта задача выполняется" / "эта задача выполнена и вот результат).
Если я правильно понял вопрос!!!
У браузеров есть ограничение, обычно 4-5 запросов к одному домену.
Если у вас на этом домене есть "тяжелый" скрипт, который выполняется долго, то браузер поставит его в очередь, дальнейшие запросы "лехкие" так же будут висеть, ожидая завершение тяжелого запроса
Можно это обойти, поставим этот "тяжелый" скрипт на другой домен, или же через alias, так что бы URL домена сменился.
Для теста накидал скрипт, для эмуляции этого поведения
HTML
<button type="button" class="btn" onclick="test(1)">Кнопка1 - тяжелый другой домен</button>
<button type="button" class="btn" onclick="test(2)">Кнопка2 - тяжелый текущий домен</button>
<button type="button" class="btn" onclick="test(0)">Кнопка0 - лехгий текущий домен</button>
JS
function test(param) {
let options = {
url : 'http://example.com/test.phtml', // Текущий домен
data : {param : param},
type : 'POST',
success : function () {
console.log('success');
}
};
if (param == 1) {
options.url = 'http://www.example.com/test.phtml' // Другой домен
}
$.ajax(options);
}
PHP : test.phtml
<?php
// для крос запроса
header('Access-Control-Allow-Origin: *');
$param = $_REQUEST['param'];
if ($param == 1) {
// Имитации тяжелого запроса (Другой сервер)
sleep(5);
} else if ($param == 2) {
// Имитации тяжелого запроса (текущий сервер)
sleep(5);
} else {
// быстрое выполение
}
Если по кликать по кнопке Кнопка2 несколько раз, а далее по Кнопке0, то вы будите ждать выполнение.
А если такое же проделать Кнопка1 и Кнопка0, то ждать не будите
Сборка персонального компьютера от Artline: умный выбор для современных пользователей