ЗАКАЗ

Ошибки php PDO при длительных операциях

Описание проблемы

Один из скриптов (problem_script.php), который мне приходилось отлаживать, иногда завершался ошибками PDO.

Сначала, при запросах на выборку данных, выбрасывались предупреждения:

PHP Warning: PDO::query(): MySQL server has gone away in problem_script.php.php on line 67
PDO::query(): Error reading result set's header in problem_script.php on line 67
PHP Warning: Invalid argument supplied for foreach() in problem_script.php on line 67

После следовал запрос на обновление данных и скрипт завершался критической ошибкой:

PHP Fatal error: Call to a member function fetch() on a non-object in problem_script.php on line 93

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

Первым в скрипте создавалось подключение к MySQL БД, после следовал длительный обмен с сервисом 1С и обрабатывался ответ, а затем выбирались и обновлялись данные в MySQL базе данных используя PDO. Объем передаваемой информации из 1С рос постепенно, ошибки возникали все чаще.

Причина

Причина оказалась не совсем очевидной, но решение было очень простым: В настройках mysql есть опции wait_timeout - время в секундах, в течении которого mysql серевер ждет действий от неактивных подключений, пока их не закроет. Время выполнения php скрипта было установлено в 600 сек, а wait_timeout = 300 сек. При этом скрипт мог выполнятся и более 5 мин, завершаясь без ошибок, если обмен с 1С занимал менее wait_timeout

Способ решения

В моем случае мне даже не пришлось ничего настраивать, я просто перенес конструкцию

$dbh = new PDO($host, $user, $pass);
ниже, после блока длительных операции обмена данным с 1C, и ошибки прекратились.

Выводы:

Далеко не все выбрасываемые ошибки php интуитивно понятны, еще сложнее становится когда проблема возникает не каждый раз и зависит от сторонних сервисов. Надо быть настойчивым и терпеливым чтоб разобрать весь скрипт на кусочки и найти закономерности в появлении ошибок.