stale-while-revalidate و stale-if-error: خلي الكاش يخبّي بطء الـ API وأعطاله
إزاي directives صغيرة في Cache-Control ترجّع رد قديم شوية بدل ما المستخدم يستنى أو يشوف error، ومتى تستخدم private، بأمثلة MDN.
الـ API بتاعك بطيء ساعات، أو بيقع دقيقتين في الأسبوع، والمستخدم في الآخر بيشوف loading طويل أو صفحة error. فيه directives صغيرة في Cache-Control ممكن تخبّي جزء كبير من ده من غير ما تغيّر سطر في الكود: stale-while-revalidate و stale-if-error. ده الجزء ٣٥ من «Full Stack Tips»، وهو تكملة للجزء ٤ اللي اتكلمنا فيه إن no-cache مش معناها «ما تخزنش».
الأساس: max-age
أي رد ليه فترة يكون فيها fresh، والكاش يقدر يرجّعه من غير ما يسأل السيرفر. المثال من MDN:
Cache-Control: max-age=604800
يعني الرد fresh لمدة 7 أيام (604800 ثانية). خلي بالك إن MDN بتوضح إن الـ max-age بيتحسب من وقت ما الرد اتعمل على السيرفر، مش من وقت ما الكاش استلمه.
بعد الـ 7 أيام الرد بيبقى stale، والطبيعي إن الطلب الجاي يستنى لحد ما الكاش يعمل revalidate مع السيرفر. وهنا بييجي دور الـ directives الجاية.
stale-while-revalidate: رجّع القديم وحدّث في الخلفية
Cache-Control: max-age=604800, stale-while-revalidate=86400
حسب MDN: الرد fresh لمدة 7 أيام، وبعدها بيبقى stale، بس الكاش مسموح له يرجّعه لأي طلب ييجي في اليوم اللي بعده (86400 ثانية)، بشرط إنه يعمل revalidate في الخلفية.
النتيجة:
- المستخدم بياخد رد فوري من الكاش
- الكاش بيكلم السيرفر في الخلفية ويرجع fresh تاني
- من ناحية المستخدم، كأن الرد كان fresh طول الوقت، ووقت الـ revalidate اتخبّى
نقطة مهمة: لو مفيش ولا طلب جه خلال فترة الـ stale دي، الرد بيبقى stale عادي، وأول طلب بعدها هيستنى revalidate عادي.
stale-if-error: رجّع القديم لما السيرفر يقع
Cache-Control: max-age=604800, stale-if-error=86400
الـ directive دي بتقول للكاش إنه يقدر يرجّع رد stale لما السيرفر يرجّع error، أو لما الـ error يحصل محليًا. وMDN بتعرّف الـ error هنا إنه أي رد بـ status code:
- 500
- 502
- 503
- 504
في المثال: الرد fresh لمدة 7 أيام، وبعدها ممكن يتستخدم يوم كمان لو حصل error. ولما فترة الـ stale-if-error تخلص، المستخدم هيستلم الـ error زي ما هو.
وفيه نسخة من stale-if-error كـ request header، بس MDN بتقول إنها مش مدعومة في أي متصفح. الكلام كله هنا على الـ response header اللي السيرفر بيبعته.
private: لما الرد فيه بيانات المستخدم
Cache-Control: private
قبل ما تفرح بالكاش، اتأكد إن الرد مش متخزن في المكان الغلط. private معناها إن الرد يتخزن بس في private cache زي كاش المتصفح، مش في shared cache زي الـ CDN أو الـ proxy.
MDN بتنصح تحطها لأي محتوى personalized، خصوصًا الردود اللي بعد الـ login والـ sessions اللي شغالة بالـ cookies. لو نسيتها، الرد ممكن يتخزن في shared cache ويوصل لمستخدمين تانيين.
تجمعهم إزاي؟
مثال لصفحة catalog أو config عامة مش متغيرة كل ثانية:
Cache-Control: max-age=604800, stale-while-revalidate=86400, stale-if-error=86400
ولأي endpoint بيرجّع بيانات المستخدم نفسه، ابدأ بـ private قبل أي حاجة تانية.
الأرقام هنا هي أمثلة MDN بس. ظبط المدد على حسب المحتوى بتاعك: صفحة docs تستحمل أيام، لكن عدد الـ stock أو سعر لحظي ما يستحملش.
خلي بالك
- الدعم: MDN بتقول إن الـ user agents اللي مش فاهمة الـ directives دي المفروض تتجاهلها. يعني مش هتكسر حاجة، بس كمان ممكن ما تشتغلش. شيّك على جدول التوافق وعلى توثيق الـ CDN اللي بتستخدمه.
- مش لكل البيانات: أي حاجة لازم تبقى لحظية (رصيد، أسعار، صلاحيات) ما ينفعش ترجع قديمة حتى لثواني.
- المرجع الأصلي: الـ directives دي متعرّفة في RFC 5861 بعنوان HTTP Cache-Control Extensions for Stale Content.
رأيي
stale-while-revalidate من أرخص التحسينات اللي ممكن تعملها في الـ latency اللي المستخدم حاسس بيها: header واحد، من غير cache layer جديدة ولا تغيير في الكود. وstale-if-error بتديك شبكة أمان بسيطة وقت ما الـ backend يقع لدقايق. بس الأهم من الاتنين إنك تفكر الأول: الرد ده عام ولا خاص؟ لأن كاش سريع لبيانات غلط أسوأ من مفيش كاش.
وإنت، بتستخدم stale-while-revalidate في الـ CDN أو الـ API بتاعك؟
المصادر
- Web Dev
- HTTP
- Caching
- CDN
- Performance
- Backend