الخطأ 504 يعني أن الصفحة كانت ما تزال تُبنى حين توقّف Nginx عن الانتظار. لم ينهر شيء. بل استغرق شيءٌ ما وقتًا أطول ممّا يُسمح له، والسؤال الصادق هو: ما هو.

جِد الطلب البطيء

يكتب PHP-FPM سجلًّا للبطء إن طلبت منه ذلك، ويطبع الدالة التي كانت تعمل بالضبط حين نفدت الساعة. وهذا هو الجواب كلّه، فشغّله قبل أن تغيّر أي شيء آخر.

; in the pool config
request_slowlog_timeout = 5s
slowlog = /var/log/php8.3-fpm-slow.log
  1. أعِد تحميل PHP-FPM — systemctl reload php8.3-fpm
  2. أعِد إنتاج الصفحة البطيئة — طلبٌ واحد يكفي.
  3. اقرأ الأثر — tail -60 /var/log/php8.3-fpm-slow.log — والإطار الأعلى هو ما كان يعمل.

الأشياء الثلاثة التي يكون هو غالبًا

  • نداءٌ خارجيّ بلا مهلة. بوّابةُ دفعٍ أو واجهةٌ برمجية كفّت عن الإجابة ستُمسك صفحتك ما دام المقبس مفتوحًا. كل طلب صادر يحتاج مهلته الخاصّة، وخمس ثوانٍ كرمٌ.
  • واستعلامٌ بلا فهرس. فجدولٌ كان صغيرًا العام الماضي ليس صغيرًا الآن. وسجلّ الاستعلامات البطيئة يسمّيه.
  • ودورةٌ على مجلّد. فمجلّدٌ نما إلى مئة ألف ملفّ يستغرق سرده دقائق.
ورفعُ fastcgi_read_timeout يُذهب الخطأ ويترك الزائر يحدّق في تبويب فارغ خمس دقائق بدل دقيقة. أصلح الانتظار لا الحدّ.

ومتى يكون رفعه صوابًا

حالةٌ واحدة: مهمّةٌ طويلة مقصودة أطلقتها أنت — ترحيلٌ أو استيرادٌ كبير — على صفحة لا يستعملها غيرك. ارفعه لذلك الموضع وحده، لا عالميًّا أبدًا.

location = /admin/import.php {
    fastcgi_read_timeout 600;
}
وكل ما يستطيع زائرٌ إطلاقه مكانه طابور. تبدأ الصفحة المهمّة وتعود فورًا؛ والمهمّة تبلّغ حين تنتهي.