Как предотвратить истечение времени ожидания браузера (длинный PHP-скрипт)

PHP-скрипт выполняется за 25 секунд (для 1 человека) и, возможно, дольше при высоком трафике. Я не хочу, чтобы время ожидания браузера истекло (PHP этого не сделает — я set_time_limit(0);).

Может ли кто-нибудь предоставить пример кода, как убедиться, что время ожидания браузера не истекло (или подробно объяснить, что делать)? Какой лучший метод? Аякс?

Спасибо.

ИЗМЕНИТЬ:

Брайан Грэм говорит: «Как только javascript запускает запрос ajax, он работает до тех пор, пока не завершится, не завершит работу или не выдаст ошибку. Насколько я знаю, он должен делать это даже в том случае, если пользователь покидает страницу».

Итак, могу ли я просто вызвать длинный PHP-скрипт через Ajax, а затем он будет работать столько времени, сколько потребуется, без тайм-аута (даже если скрипт ничего не вернет)?


person Hope4You    schedule 02.03.2012    source источник
comment
^ согласен. Вы найдете людей гораздо более полезными в стеке, когда они увидят, что вы действительно принимаете и даете им репутацию, когда они не торопятся, чтобы помочь вам с вашими проблемами;)   -  person Brian    schedule 03.03.2012
comment
Что вам нужно, так это профилирование, чтобы вы могли узнать, какие части вашей страницы занимают много времени. Затем вы можете ускорить эти части.   -  person Arjan    schedule 03.03.2012
comment
Вот в чем дело - около 3/4 времени уходит на связь с удаленным сервером. Скорость этого сервера никогда не меняется, независимо от того, сколько трафика у моего сайта. Как вы думаете, будет ли у браузера когда-либо возможность тайм-аута при большом трафике, даже если я напрямую запущу скрипт через URL-адрес?   -  person Hope4You    schedule 03.03.2012


Ответы (3)


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

Лучший способ реализовать что-то подобное, который я нашел, — установить ignore_user_abort и отключить ограничение по времени. Таким образом, вы можете позволить скрипту работать в фоновом режиме. Таким образом, скрипт может продолжать работать, пока пользователь просматривает ваш сайт. Им даже не обязательно оставаться на одной волне. Таким образом, вы запускаете запрос с помощью AJAX, чтобы запустить его. Имейте цикл в этом скрипте, который обновляет ход сеанса пользователя.

ini_set('session.use_cookies', 0); //don't spam the user with cookies for each session_start()
while( ... ) {
    session_start();
    //update status to the user's session
    session_write_close();
    //sleep or whatever
}

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

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

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

person Brian    schedule 02.03.2012
comment
Это выглядит как лучшее решение для меня. Запустите процесс через Ajax, затем используйте Ajax для проверки значения сеанса, и после завершения процесса отобразите результат. Это должно предотвратить истечение времени ожидания браузера, поскольку процесс все равно будет выполняться, даже если он будет прерван браузером. - person Hope4You; 03.03.2012
comment
Это правильно :), пока вам не нужно напрямую возвращать какие-либо результаты из этого скрипта в браузер, это работает. Если вам нужно записать какие-либо выходные данные в браузер, вам нужно будет написать свой собственный канал связи, который использует систему опроса, подобную Comet, для получения обновлений из сеанса. Удачи ;) - person Brian; 03.03.2012

Вам нужно будет инициировать основной процесс с запросом AJAX, а затем постоянно опрашивать сервер, чтобы проверить его ход. Невозможно сказать браузеру, чтобы он не истекал по тайм-ауту. (И это понятно. Если бы мой браузер завис на 5 минут, я бы совсем запутался.)

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

person Corbin    schedule 02.03.2012
comment
Я не очень понимаю, как делать статусные вещи. Будет ли это простое решение работать так же хорошо? - запустите процесс через Ajax, а затем каждые несколько секунд используйте Ajax для запроса пиксельного gif с сервера (что угодно, чтобы поддерживать соединение). Будет ли это держать сценарий подключенным? (Я буду использовать onreadystatechange, чтобы узнать, когда процесс завершится). - person Hope4You; 03.03.2012
comment
Как только javascript запускает запрос ajax, он работает до тех пор, пока не завершится, не завершит работу или не выдаст ошибку. Насколько я знаю, он должен делать это даже в том случае, если пользователь покидает страницу. - person Brian Graham; 03.03.2012
comment
Поддерживаемое соединение будет зависать на большом запросе. Постоянные соединения завершают запрос перед переходом к следующему. Самый простой (хотя, возможно, и не лучший) способ выполнить процесс (хотя вы должны рассмотреть некоторые предложения Джонатона Хиббарда, чтобы попытаться выяснить, почему сценарий занимает так много времени), — это создать файл с любым идентификатором состояния в начало сценария, а затем удалите файл в конце сценария. Ваша проверка состояния тогда будет просто: если файл существует, он все еще работает, в противном случае завершен. - person Corbin; 03.03.2012
comment
@BrianGraham, могу ли я запустить длинный сценарий через Ajax, и он завершится независимо от того, сколько времени это займет (даже минуты)? Для каждого браузера? - person Hope4You; 05.03.2012
comment
Я не уверен, что закрытие браузера убьет запущенный процесс php, но пока ajax совместим со всеми браузерами, проблем быть не должно. Во всяком случае, используйте команды php system или passthru, чтобы перевести его в фоновый режим php, вообще не требуя присутствия пользователя (гарантировано). - person Brian Graham; 05.03.2012
comment
Закрытие браузера не всегда убивает скрипт, хотя иногда это происходит, в зависимости от того, как Apache обрабатывает разъединяемый запрос. Запуск его в фоновом режиме, безусловно, лучший вариант, и я предположил, что это подразумевалось в моем ответе. Кроме того, не забывайте, что запросы AJAX также имеют тайм-аут. Браузер может убить запрос до того, как это сделает сервер. - person Corbin; 06.03.2012

Если вы не хотите, чтобы время ожидания браузера истекло, то вот единственные решения, которые я могу для вас придумать.... Просто знайте: я установил время ожидания php через 10 секунд. Если для обработки требуется больше времени - никогда - тогда сценарий не подходит для пользователей, посещающих мой сайт.

1) Оптимизируйте свой код. Узнайте, какая часть вашего кода занимает слишком много времени, и определите, что вы можете сделать, чтобы сделать его быстрее.

2) Используйте решение push/pull. Отправьте запрос на сервер и скажите ему выполнить приложение. Приложение ставится в очередь на выполнение, и сервер возвращает идентификатор процесса. Демон на сервере проверяет очередь и выполняет скрипт из cli, а не из браузера.

3) создавать отдельные подпрограммы, требующие отдельных вызовов методов в стиле ajax. Вызовите подпрограмму 1, чтобы запустить фрагмент скрипта. Вызовите подпрограмму 2, чтобы сделать еще один запрос ajax, и запустите второй после завершения первого. и т.п.

4) честно - я бы просто нашел другое решение. очевидно, что если ваш скрипт выполняется так долго, что-то ужасно не так...

person Jonathon Hibbard    schedule 02.03.2012
comment
Большую часть времени (вероятно, около 3/4) связывается с удаленным сервером, скорость которого я не могу контролировать. - person Hope4You; 03.03.2012
comment
Опять же, это то, что вы захотите выделить. Создание очереди, которая обрабатывается скриптом демона/хрона или чем-то еще, что вы хотите сделать, — это то, как вы берете ее под свой контроль. В конце концов, вы должны задать себе вопрос: будут ли пользователи ждать, пока я получу ответ, или они покинут мою страницу до того, как я смогу дать им ответ. - person Jonathon Hibbard; 03.03.2012
comment
Будем надеяться, что они подождут — скрипт действительно используется для обработки заказа! Вот почему я слежу за тем, чтобы время ожидания браузера не истекло. Спасибо за помощь. - person Hope4You; 03.03.2012
comment
У вас есть 2 проблемы: если они ждут, и время ожидания браузера или сервера истекает, и вы, и они облажались.. Если они не ждут, они могут или не могут быть облажались, но вы подвергаетесь еще большему риску, поскольку пользователи не тратят время на медленные сайты. Если они собираются ждать, то уведомление о том, что это должно быть готово через 5 минут, по крайней мере, говорит им, что мои вещи требуют времени. Вернитесь позже и проверьте статус или напишите вам письмо, когда все будет готово. Медленные сайты = низкий трафик = вы теряете (и, возможно, теряете деньги). просто говорю =) - person Jonathon Hibbard; 03.03.2012