PHP-FPM Ошибка: child dynamic execution timed out (request_terminate_timeout)
Механизм защиты от зависших скриптов (Execution Timeout Guard)
Мастер-процесс PHP-FPM осуществляет постоянный контроль длительности выполнения запросов каждым воркером пула. Если обработка PHP-скрипта превышает лимит времени, заданный системной директивой request_terminate_timeout в конфигурации пула (или max_execution_time в php.ini), мастер-процесс считает воркер зависшим, принудительно убивает его системным сигналом SIGTERM (а при отсутствии реакции — SIGKILL) и регистрирует ошибку:
«WARNING: [pool www] child 14502, script '/var/www/html/index.php' (request: "POST /api/export") execution timed out (60.104921 sec), terminating»
Веб-сервер Nginx, не дождавшись FastCGI-ответа от разорванного соединения, мгновенно возвращает клиенту ошибку HTTP 502 Bad Gateway или HTTP 504 Gateway Time-out.
Бизнес-риски
Невозможность генерации объемных актов сверок и прайс-листов, срыв интеграций с маркетплейсами и платежными шлюзами по таймауту.
Иерархия и взаимодействие таймаутов веб-стека
| Уровень стека | Директива конфигурации | Поведение при срабатывании |
|---|---|---|
| Веб-сервер Nginx | fastcgi_read_timeout 60s; | Nginx закрывает клиентское соединение и отдает HTTP 504 (PHP скрипт продолжает работать в фоне!). |
| Мастер PHP-FPM | request_terminate_timeout = 60s | Мастер физически убивает воркер PHP, останавливая нагрузку на CPU/БД. |
| Ядро PHP Engine | max_execution_time = 30 | PHP бросает Fatal Error (учитывает только CPU-время, не считает сетевые сокеты и sleep!). |
Регламент локализации зависших операций и синхронизации таймаутов
Шаг 1: Активация Slow-лога для поиска точной строки зависания
Настройте логирование медленных запросов с автоматическим снятием PHP-стека вызовов:
# 1. Откройте конфигурацию пула:
sudo nano /etc/php/8.2/fpm/pool.d/www.conf
# 2. Настройте параметры slowlog:
slowlog = /var/log/php8.2-fpm.slow.log
request_slowlog_timeout = 5s
request_slowlog_trace_depth = 20
# 3. Перезапустите службу и анализируйте лог:
sudo systemctl reload php8.2-fpm
sudo tail -f /var/log/php8.2-fpm.slow.logВ Slow-логе вы увидите точный стек вызовов: например, зависание в функции file_get_contents(), curl_exec() или ожидание тяжелого SQL-запроса в PDO::query().
Шаг 2: Синхронное увеличение таймаутов для длительных операций
Если операция действительно требует длительного выполнения (например, импорт файла 500 МБ):
# 1. В пуле PHP-FPM (/etc/php/8.2/fpm/pool.d/www.conf):
request_terminate_timeout = 300s
# 2. В php.ini (/etc/php/8.2/fpm/php.ini):
max_execution_time = 300
max_input_time = 300
default_socket_timeout = 300
# 3. В конфигурационном блоке Nginx (/etc/nginx/sites-available/default):
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_read_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_connect_timeout 60s;
}
# 4. Проверка и перезагрузка веб-стека:
sudo nginx -t && sudo systemctl reload nginx
sudo systemctl reload php8.2-fpmШаг 3: Настройка таймаутов на уровне внешних cURL и сокет-соединений в PHP
Защитите PHP-код от бесконечных блокировок сторонними API:
// ПРАВИЛЬНО: явная установка сетевых таймаутов в cURL:
$ch = curl_init('https://api.external-service.com/data');
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // Таймаут на TCP handshake (сек)
curl_setopt($ch, CURLOPT_TIMEOUT, 15); // Максимальное время всего ответа (сек)
$response = curl_exec($ch);Типовые ошибки администраторов
- Увеличение таймаута в Nginx без увеличения request_terminate_timeout в FPM: Nginx будет ждать 300 секунд, но FPM убьет скрипт ровно через 60 секунд, выдав клиенту ошибку 502 Bad Gateway.
- Использование синхронных HTTP-запросов для тяжелых фоновых задач: Длительные выгрузки должны обрабатываться асинхронными очередями (RabbitMQ, Redis Queue / Celery), а не в рамках HTTP-запроса пользователя.
Инженеры ITSTM проведут профилирование через Blackfire/Xdebug, устранят блокирующие вызовы и переведут долгие процессы на асинхронные очереди.
Частые вопросы (FAQ)
Почему max_execution_time не останавливает скрипт при зависании cURL?
В ОС Linux max_execution_time отслеживает только процессорное время (CPU User/System Time). Ожидание ответа сети (I/O Wait) не расходует CPU, поэтому скрипт может висеть до сработки request_terminate_timeout или default_socket_timeout.
Как переопределить request_terminate_timeout для одного конкретного URL?
Создайте отдельный location в Nginx для тяжелого URL и перенаправьте его в отдельный пул PHP-FPM с увеличенным request_terminate_timeout.
Что означает статус terminate in progress в логах FPM?
Мастер отправил сигнал завершения воркеру, но процесс не может завершиться (например, заблокирован в системном вызове драйвера диска/сети). После короткой паузы мастер отправит SIGKILL.
Влияет ли fastcgi_ignore_client_abort на таймаут?
Да, если клиент закрыл вкладку браузера, при fastcgi_ignore_client_abort on скрипт продолжит выполняться до достижения request_terminate_timeout.