Nginx + PHP-FPM 架構下,max_execution_time、set_time_limit() 有時失效,真兇往往是 PHP-FPM 自身的 request_terminate_timeout 或 Nginx 反向代理超時設定。本文完整記錄一次 504 Gateway Timeout 排查實戰。
php.ini: max_execution_time、ini_set()、set_time_limit()(僅計算 CPU 時間,不含 I/O 等待)。php-fpm.conf: request_terminate_timeout(硬性殺掉超時 Worker 進程,預設 30s)。proxy_read_timeout、proxy_send_timeout、proxy_connect_timeout(預設 60s)。導出 500 筆資料,約 150 筆時 Nginx 拋 504。觀察約 30 秒超時,但 php.ini 已設 max_execution_time = 300。
<?php
echo 'aaa';
set_time_limit(0); // 0 = 無限制
sleep(40);
echo 'aa';
?>
結果:依然 30 秒超時 → set_time_limit 失效。
# php-fpm.conf
<value name="request_terminate_timeout">30s</value>
官方文檔:「當 max_execution_time 無法停止腳本時生效,預設 5s,0s 代表關閉」。此參數為**硬性殺進程**,優先級高於 PHP 內部計時。
# 方案一:調大至業務所需(如 300 秒)
<value name="request_terminate_timeout">300s</value>
# 方案二:關閉(生產環境建議設定具體值,防止佔用 Worker)
<value name="request_terminate_timeout">0s</value>
修改後 **reload php-fpm** 生效,程式正常跑完 40 秒睡眠。
若使用 upstream 負載均衡,必須同步調整:
location / {
proxy_pass https://backend;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s; # 最關鍵:讀取 FastCGI 回應的超時
# fastcgi_read_timeout 300s; # 若直接 fastcgi_pass
}
max_execution_time ≤ PHP-FPM request_terminate_timeout ≤ Nginx proxy_read_timeout。request_terminate_timeout 觸發次數,發現長耗時腳本優化或異步化。max_execution_time 開始計入部分系統呼叫時間,但仍不含網路 I/O,PHP-FPM 層防線不可少。搞懂三層超時關係,不再為莫名的 504、502 發呆,長任務乖乖走佇列才是正道。