Лучшая практика, чтобы найти источник завершения PHP-скрипта - PullRequest
6 голосов
/ 25 ноября 2010

У меня есть PHP-скрипт, который извлекает часть данных из базы данных, обрабатывает ее, а затем проверяет, есть ли еще данные. Этот процесс выполняется бесконечно, и я запускаю несколько из них одновременно на одном сервере.

Это выглядит примерно так:

<?php
    while($shouldStillRun)
    {
       // do stuff
    }
    logThatWeExitedLoop();
?>

Проблема в том, что через некоторое время процесс останавливается, и я не смог отладить его и определить причину.

Вот что я использую для получения информации:

  • error_log - Ведение журнала всех ошибок, но ошибки не отображаются в журнале ошибок.
  • register_shutdown_function - Зарегистрированная пользовательская функция выключения. Это действительно вызывается, так что я знаю, что сервер не убивает процесс, ему разрешено завершить. (или, по крайней мере, я предполагаю, что это так?)
  • debug_backtrace - Записал debug_backtrace () в мою пользовательскую функцию выключения. Это показывает только один вызов, и это моя пользовательская функция выключения.
  • Журнал, если достигнут конец скрипта - Вне цикла у меня есть функция, которая регистрирует, что скрипт вышел из цикла (и, следовательно, обычно достигнет конца исходного файла). Когда сценарий умирает случайно, он не регистрирует это, поэтому все, что его убивает, убивает его, пока он находится в середине обработки.

Какие другие методы отладки вы бы предложили для поиска виновника?

Примечание: я должен добавить, что это не проблема с max_execution_time , который отключен для этих сценариев. Время до того, как быть убитым, противоречиво. Он может работать в течение 10 секунд или 12 часов, прежде чем он умрет.


Обновление / Решение : Спасибо всем за ваши предложения. Записав выходные данные, я обнаружил, что при сбое запроса MySql сценарий был настроен на die (). D'о. Обновил его, чтобы регистрировать ошибки MySQL и затем завершить. Теперь все работает как шарм!

Ответы [ 6 ]

2 голосов
/ 25 ноября 2010

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

2 голосов
/ 25 ноября 2010

Помните, в PHP есть переменная, которая говорит, как долго должен выполняться скрипт. Макс-исполнение времени

Убедитесь, что вы не собираетесь это делать, или используйте set_time_limit (), чтобы увеличить время выполнения. Эта программа работает через веб-сервер или через Cli?

Добавление: Мой плохой опыт работы с PHP. Просматривая некоторые фоновые сценарии, которые я написал ранее в этом году. Извините, но PHP - ужасный язык сценариев, позволяющий делать что-либо в течение длительного времени. Я вижу, что более новый PHP (до которого мы не обновились) добавляет функциональность для запуска GC. У меня проблема с использованием слишком большого количества памяти, потому что GC почти никогда не запускается для очистки себя. Если вы используете вещи, которые ссылаются на себя рекурсивно, они также никогда не будут освобождены.

Создание массива из 100 000 элементов создает память, но затем установка массива в пустой массив или его объединение, НЕ освобождает его немедленно и не помечает как неиспользуемый (иначе создание нового массива из 100 000 элементов увеличивается память).

Моим личным решением было написать Perl-скрипт, который работал вечно, и system ("php my_php.php"); при необходимости, чтобы переводчик освободился полностью. В настоящее время я поддерживаю 5.1.6, это может быть исправлено в 5.3+ или, по крайней мере, теперь у них есть команды GC, которые можно использовать для принудительной очистки GC.

Простой скрипт

#!/usr/bin/perl -w

use strict;

while(1) {
  if( system("php /to/php/script.php") != 0 ) {
    sleep(30);
  }
}

тогда в вашем php скрипте

<?php

// do a single processing block

if( $moreblockstodo ) {
  exit(0);
} else {
  // no? then lets sleep for a bit until we get more
  exit(1);
}

?>
0 голосов
/ 25 ноября 2010

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

0 голосов
/ 25 ноября 2010

Я сталкивался с этим раньше на одном из наших проектов на работе. У нас похожая настройка - PHP-скрипт проверяет БД, если есть задачи, которые необходимо выполнить (например, отправка электронного письма, обновление записей, обработка некоторых данных). В скрипте PHP есть цикл while, который установлен на

while(true) {
    //do something
}

Через некоторое время скрипт тоже будет как-то убит. Я уже попробовал большинство из того, что было сказано здесь, например, установление max_execution_time, использование var_export для записи всего вывода, размещение try_catch, вывод скрипта (php ...> output.txt) и т. Д. выясните, в чем проблема.

Я думаю, что PHP просто не предназначен для самостоятельного выполнения фоновых задач. Я знаю, что это не ответ на ваш вопрос (как отладить это), но способ, которым мы работали, заключается в том, что мы использовали cronjob для вызова файла PHP каждые 5 минут. Это похоже на ответ Джереми об использовании сценария perl - он гарантирует, что интерпретатор освободится после выполнения.

0 голосов
/ 25 ноября 2010

Похоже, что бы ни происходило, это не стандартная ошибка php.Вы должны иметь возможность выдавать свои собственные ошибки, используя оператор try ... catch, который затем должен регистрироваться.У меня нет больше информации, кроме этого, потому что я нахожусь на моем телефоне вдали от компьютера.

0 голосов
/ 25 ноября 2010

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

Содержимое большинства переменных можно получить в виде строки с помощью var_export , используя форму var_export($varname,true).

Вы можете просто записать это в определенный файл и следить за ним.Последнее состояние функции перед окончанием журнала должно дать некоторые подсказки.

...