Есть скрипт, который нереально выполнить за один проход, он очень тяжёлый и вешает сервер. Поэтому я разбил его на части таким способом: PHP: $per_page=5;// операций на одну страницу if(!$_GET['pageid']){ $_GET['pageid']=1; } $_GET['pageid']=mysql_real_escape_string($_GET['pageid']); $from=$per_page*($_GET['pageid']-1); $limit=$from.', '.$per_page; $query=mysql_query("SELECT COUNT(`id`) AS `numb` FROM `users_stats`"); @$row2=mysql_fetch_array($query,MYSQL_ASSOC); $query=mysql_query("SELECT `id` FROM `users_stats` ORDER BY `id` LIMIT $limit"); while($row=mysql_fetch_array($query,MYSQL_ASSOC)){ $stats->write_cache($row['id']); // мой неподъёмный говнокод } if($from>=$row2['numb']){ die('Я сделяль!'); } $from=$from+$per_page; if($from>$row2['numb']){ $from=$row2['numb']; } echo' Пересчитываю записи: '.$from.' из '.$row2['numb'].' <script type="text/javascript"> window.location.href="/stats.php?pageid='.($_GET['pageid']+1).'"; </script>'; die; Тут редирект происходит в конце выплёвыванием JS на страницу, то есть для этого нужен клиент. А для крона можно сделать нечто подобное? PHP-цикл здесь не прокатит, он повесится в конечном счёте, ругнувшись на Allocated memory. Поэтому нужно чтобы что-то дёргало PHP-скрипт до тех пор, пока тот не скажет "Я сделяль!" или как-то ещё сообщит о завершении работы.
Да это не важно абсолютно. Нужно выполнять PHP-файл бесконечно, пока он не скажет "стоп". При этом PHP-файл будет записывать позицию где он остановился в БД например, и каждый раз продолжать с того места.
Я пока вот что придумал. Можно сделать чтобы крон запускал файл раз в минуту например, а файл не выполнялся когда это не нужно. В файле будет такой алгоритм: Проверяем есть ли в БД флажок - working = true. Если есть, то die. Выставляем тот самый флажок working = true и начинаем работать. Проверяем текущее время, если оно НЕ ночное, то working = false и die. Проверяем дату составления последнего кэша. Если оно менее 7 часов, то working = false и die. Отрабатываем цикл, пишем позицию где остановились в БД. Если достигли конца, то ставим в БД позицию на 0, обновляем дату составления кэша. working = false и die. Не знаю, может есть варианты проще. memory_limit не предлагать.) Хостинг не позволяет сменить, да и не хватит там оперативки. Даже у меня на компе с лимитом памяти в 2гб, этот скрипт не выполняется за раз.
а header отменили ? А почему ты используешь подключение к бд старого образца .... Читай pdo. Этот скрипт не тяжёлый. Проверь свои запросы, к mysql они верно работают ? Может быть там глюки какие то может вешаться потому что скрипт не выполняется. Крон программа тупая, она делает то что ты ей говоришь. Она не чё не придумывает. Ты ей сказал так она и пытается так делать, если у тебя виснит сервер крон в этом не виноват, и не в объёме кода дела. У тебя ошибка протестируй свой код. Без использования крона чтобы отладить его. Отладь проверь его на скорость срабатывания за какой промежуток времени у тебя срабатывает код, и через какой промежуток времени ты гоняешь его по крону. --- Добавлено --- ты говорил что у тебя, там 13к строк. Вопрос на засыпку, ты кроном дёргаешь непосредственно файл php с 13к строками. Если да то это ты вообще дал прямо лихо. ?
@NerdRage в долгих процессах самое засадное это ситуация когда что-то пошло не так. чем дольше процесс/серия процессов работает, тем вероятнее что что-то вторгнется и испортит песню. в качестве "флажка" в базе ты можешь использовать именованый лок. преимущество в том, что обрыв соединения автоматически освободит лок. а твой ручной флажек может остаться и требовать ручного вмешательства. вместо "пишем позицию где остановились" лучше использовать натуральное значение из таблицы где у тебя результаты работы. какой-то max(field). иначе может возникнуть ситуация когда скрипт аварийно не достиг места где "пишется позиция" и ты не будешь знать с какого места продолжить. ну и, конечно, innodb + транзакции и чтобы данные оставались непротиворечивыми.
А посмотреть, что там так жрёт память? и по идее, есть способы освободить память досрочно (unset, к примеру, приводит в действие, в конечном итоге, сборщик мусора).
@mkramer да нихрена он не приводит, 7 пых вроде научился правильно мусор собирать, хотя ещё не возникало на нем задачи обработать большие объемы, а 5.* просто путается в ссылках, unset и правильно прописанные дестркуты, даже с принудительным вызовом сборщика не приводят к нормальному высвобождению памяти. В результате на каком-то этапе процесс начинает тормозить под своей тяжестью, даже если ресурса сервера ещё не исчерпаны. Как побороть это я так и не понял, потому взял и переписал всё на go ) Правда эта хрень наступает, когда приходится вертеть гигабайтами и миллионами записей. На 13к скорее кривые руки виноваты, да )
--- Добавлено --- Тут и кривые руки и размер алгоритма (функция около 3 тыщ строк). Выполнено оно не лучшим образом, это да, есть лишние циклы. Но я уверен, что даже если переписать всё идеально, то при прогоне этой функции циклом для 800+ юзеров, скрипт всё-равно повесится. Так что, только разбивать на части. --- Добавлено --- Если делать редирект через header, таким способом: PHP: header('Location: /stats?pageid='.($_GET['pageid']+1)); То вот результат:
так перенаправление должно быть раз в несколько секунд, делаешь задачу секунд 10-20, потом только перенаправление
@NerdRage задержка будет при выполнении заданий, можешь через каждые 100 запросов смотреть не прошло ли 10 секунд и если прошло, то делать редирект
@askanim скрипт долго у него выполняется, вот через браузер сделает чтобы он сам себя перезапуска. Лучше через cron конечно.
@denis01 капец это бред какой-то, я даже не думал о таком никогда, что так как - то запускать скрипт, это же зацикливание, вот он и висит у него, он зациклил там через не сколько операций, сервер думает что его зациклили и выдаёт ошибку. Так нельзя..... вообще ни как делать... Он перегружает ппц как сервер.... Конечно висит. Для чего крон придумали. header не для этого точно, я понимаю отправить ну один раз ещё куда не шло, и то всё равн овсе даже на один через крон реализуют это. А это какой то прям что-то.... Это ТРЕШ!
@askanim, сдерживай такие реакции. Используется во вполне профессиональных продуктах перезапуск скрипта через браузер, при выполнении длительных операций. Например, когда прогресс надо показывать в окошке пользователю. Правда, не через header. Да и ошибка, которую показал ТС, она не сервером сгенерирована, как ты пишешь, а браузером - ему просто надоело редиректы делать
Браузер ругается когда новый адрес совпадает со старым. Я не знаю как ТС сумел добиться этого при …pageid='.($_GET['pageid']+1) видимо реальность немного сложнее, чем здесь показано. логирование и дебаг, логирование и дебаг — повторять до просветления
В поддержку @askanim Именно такой и должна быть реакция в данном случае. Когда браузер делает запросы к серверу что бы узнать статус выполнения задачи или прогресс - это нормально. Когда выполнение напрямую зависит от браузера и количества редиректов которых ему не лень сделать - это адовая криворукость. Даже если продукт при этом профессиональный. В последнем случае вообще непонятно, почему бы профессионалам не заюзать сервис очередей и не решить этим все проблемы разом )
Может особенность FireFox-а. Если делать как в первом посте, через JS, то всё нормально. Я о таком методе узнал из софтины MySQLDumper. Она, в отличии от phpMyAdmin, плевать хотела на ограничивающие диррективы в php.ini, при загрузке большого SQL-файла она рубит его на части и импортирует кусками. Способ довольно крутой, особенно когда надо быстро что-то написать на коленке, чтобы прогнать большой объём данных.