Продолжить обработку после закрытия соединения
Есть ли способ в PHP закрыть соединение (по сути, сказать браузеру, чем больше нет данных), но продолжить обработку. Конкретное обстоятельство, о котором я думаю, заключается в том, что я хотел бы обслуживать кэшированные данные, а затем, если срок действия кеша истек, я все равно буду обслуживать кэшированные данные для быстрого ответа, закрыть соединение, но продолжить обработку для восстановления и кэширования новых данные. По сути, единственная цель - сделать сайт более отзывчивым, так как не будет случайной задержки, пока пользователь ждет регенерации контента.
UPDATE:
PLuS имеет самый близкий ответ на то, что я искал. Чтобы уточнить для пары людей, я ищу что-то, что позволяет выполнить следующие шаги:
- Страница пользовательских запросов
- Соединение открывается на сервер
- PHP проверяет, закончился ли кеш, если он еще свежий, обслуживает кеш и закрывает соединение (КОНЕЦ ЗДЕСЬ). Если истек, продолжайте до 4.
- Служить с истекшим кэшем
- Закройте соединение, чтобы браузер не ожидал большего количества данных.
- PHP восстанавливает свежие данные и кэширует их.
- PHP отключается.
UPDATE:
Это важно, это должно быть чисто PHP-решение. Установка другого программного обеспечения не является вариантом.
Ответы
Ответ 1
Наконец-то я нашел решение (спасибо Google, мне просто пришлось пытаться использовать разные комбинации поисковых запросов). Благодаря комментарию от arr1 на этой странице (это примерно две трети пути вниз по странице).
<?php
ob_end_clean();
header("Connection: close");
ignore_user_abort(); // optional
ob_start();
echo ('Text the user will see');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush(); // Strange behaviour, will not work
flush(); // Unless both are called !
// Do processing here
sleep(30);
echo('Text user will never see');
?>
Мне еще предстоит проверить это, но вкратце. Вы отправляете два заголовка, один из которых сообщает браузеру, сколько данных ожидает, чтобы сообщить браузеру о закрытии соединения (которое он будет делать только после получения ожидаемого количества контента). Я еще не тестировал это, и я не знаю, что нужен sleep(30)
.
Ответ 2
Если вы работаете под управлением fastcgi, вы можете использовать очень стильный:
fastcgi_finish_request();
http://php.net/manual/en/function.fastcgi-finish-request.php
Более подробная информация доступна в двойном ответе.
Ответ 3
Вы можете сделать это, установив ограничение по времени на неограниченное и игнорируя соединение
<?php
ignore_user_abort(true);
set_time_limit(0);
см. также: http://www.php.net/manual/en/features.connection-handling.php
Ответ 4
PHP не имеет такой постоянной (по умолчанию). Единственный способ, о котором я могу думать, - запустить задания cron для предварительного заполнения кеша.
Ответ 5
Насколько я знаю, если вы не используете FastCGI, вы не можете удалить соединение и продолжить выполнение (если только вы не получили ответ Endophage на работу, который я не смог). Таким образом, вы можете:
- Используйте cron или что-то в этом роде для планирования таких задач.
- Используйте дочерний процесс для завершения работы.
Но все ухудшается. Даже если вы создаете дочерний процесс с proc_open()
, PHP будет ждать завершения его до закрытия соединения даже после вызова exit()
, die()
, some_undefined_function_causing_fatal_error()
. Единственным обходным решением, которое я нашел, является создание дочернего процесса, который сам порождает дочерний процесс, например:
function doInBackground ($_variables, $_code)
{
proc_open (
'php -r ' .
escapeshellarg ("if (pcntl_fork() === 0) { extract (unserialize (\$argv [1])); $_code }") .
' ' . escapeshellarg (serialize ($_variables)),
array(), $pipes
);
}
$message = 'Hello world!';
$filename = tempnam (sys_get_temp_dir(), 'php_test_workaround');
$delay = 10;
doInBackground (compact ('message', 'filename', 'delay'), <<< 'THE_NOWDOC_STRING'
// Your actual code goes here:
sleep ($delay);
file_put_contents ($filename, $message);
THE_NOWDOC_STRING
);
Ответ 6
Может компилировать и запускать программы из PHP-CLI (не на общедоступном хостинге > VPS)
Кэширование
Для кэширования я бы так не сделал. Я бы использовал redis в качестве LRU cache. Это будет очень быстро (тесты), особенно когда вы скомпилируете его с помощью написанной на C.
Автономная обработка
Когда вы устанавливаете beanstalkd очередь сообщений, вы также можете делать отложенные puts. Но я бы использовал redis brpop/rpush выполнить часть очередей сообщений, потому что redis будет быстрее, особенно если вы используете PHP-клиентскую библиотеку (в пользовательском пространстве C).
Невозможно скомпилировать или запустить программы из PHP-CLI (на общедоступном хостинге)
set_time_limit
в большинстве случаев этот set_time_limit недоступен (из-за директивы safe-mode или max_execution_time
), чтобы установить 0, по крайней мере, когда на общедоступном хостинге. Также общий хостинг действительно провайдеры не любят, чтобы пользователи долго удерживали процессы PHP. В большинстве случаев предел по умолчанию установлен в 30.
Cron
Используйте cron для записи данных на диск с помощью Cache_lite. Некоторые темы stackoverflow уже объясняют это:
Также довольно легко, но все еще взломан. Я думаю, вы должны обновить ( > VPS), когда вам нужно сделать такой взлом.
Асинхронный запрос
В качестве последнего средства вы могли бы сделать асинхронный запрос кэширование данных с использованием Cache_lite, например. Помните, что для общедоступного хостинга вам не нужно задерживать много длительных PHP-процессов. Я бы использовал только один фоновый процесс, который вызывает другой, когда он достигает директивы max-execution-time
. Я хотел бы отметить время, когда начинается script, и между несколькими вызовами кеша я буду измерять потраченное время, и когда он приблизится ко времени, когда я сделаю еще один асинхронный запрос. Я бы использовал блокировку, чтобы убедиться, что работает только один процесс. Таким образом, я не буду мочиться у провайдера, и это можно сделать. С другой стороны, я не думаю, что я напишу об этом, потому что это хакка, если вы спросите меня. Когда я доберусь до этой шкалы, я перейду на VPS.
Ответ 7
Если вы делаете это для кэширования содержимого, вместо этого вы можете захотеть использовать существующее решение для кеширования, такое как memcached.
Ответ 8
Нет. Что касается веб-сервера, запрос от браузера обрабатывается механизмом PHP, и это так. Запрос длится до тех пор, как PHP.
Возможно, вы можете fork()
.