حل بديل لصفحة الصيانة - هل يمكن فعل ذلك؟

حدث خطأ في تحديثاتي

api_key = "a quick brown fox"
fetch("https://api.example.com/data", headers: { 'Authorization' => api_key })

يرجى مساعدتي في إصلاحه.

مرحباً!

أنا لا أجيب على سؤالك، أنا فقط أودّ معرفة السبب. لماذا تعتقد أنك بحاجة إلى صفحة صيانة؟ يبدو الأمر مزعجاً جداً لإعداده مقابل فائدة ضئيلة.

خوادماتي تتوقف عن العمل لمدة خمس دقائق شهرياً للتحديثات، وهذا كل شيء.

كلما قمت بإجراء تغييرات كبيرة، مثل تثبيت الإضافات على سبيل المثال، كان الأمر يستغرق أحياناً 20 دقيقة.

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

أعتقد أن هذا مجرد لمسة لطيفة نقدمها للزائر، سواء كان جديداً أم قديماً، لإعلامه بما يحدث.

إذا كان النهج الذي اقترحه كلود يستغرق بضع دقائق فقط، لكنه لا يحتاج إلى تعديل مرة أخرى، فأعتقد أن الوقت قد استُخدم بشكل جيد.

يستغرق الأمر ثوانٍ فقط إذا انتقلت إلى تثبيت الحاويتين المنفصلتين.

يمكنك حتى جدولة عملية التحويل ليلاً إذا كنت ترغب في ذلك حقاً، بينما أنت و/أو جمهورك الأساسي نائمون.

لا تحتاج إلى صفحة صيانة.

أستخدم بناء الحاويات المزدوجة خلف شبكة Cloudflare CDN. يقلل البناء المزدوج من وقت التوقف، وكلا منتدي الإنتاج الرئيسيين لديّ يتوقفان عن العمل لمدة لا تتجاوز 30 ثانية أثناء إعادة البناء. أفضّل وجود صفحة صيانة لأن صفحة “خادم الويب غير متصل” الافتراضية قبيحة ولا تقدم أي مؤشر حول المدة التي سيظل فيها الموقع غير متصل.

على سبيل المثال، لموقع على your-domain.com، ما عليّ سوى استخدام مسار عامل Cloudflare مضبوط على *yourdomain.com/* (تأكد من تضمين النجوم).

الخطوة 1: إنشاء صفحة العامل

يمكنك إعداد صفحة الصيانة في صفحة إعدادات workers & pages على Cloudflare - انقر على زر create application:

ثم استخدم قالب “مرحباً بالعالم” (Hello World):

ثم أعطه اسماً وانقر على deploy:

ثم انتقل إلى صفحة نظرة عامة لتلك صفحة الصيانة وانقر على edit code:

ولصق هذا الكود في نافذة كود worker.js (استبدل نطاقك وأي رسالة تريدها، عدّل النص، لون النص، الخلفية، إلخ):

export default {
  async fetch(request, env, ctx) {
    try {
      // Fetch the original request from your server
      const response = await fetch(request);

      // If YOUR SITE is swapping containers, it throws a 502, 521, or 530
      if (response.status === 502 || response.status === 521 || response.status === 530) {
        return returnCustomErrorPage();
      }

      // If everything is fine, return the normal forum traffic
      return response;
    } catch (e) {
      // If the server is completely unreachable
      return returnCustomErrorPage();
    }
  }
};

function returnCustomErrorPage() {
  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>System Refresh - YOUR-SITE.com</title>
      <style>
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; text-align: center; padding: 50px; color: #333; background-color: #f9f9f9; }
        h1 { font-size: 2.5em; margin-bottom: 0.5em; color: #9400D3; }
        p { font-size: 1.2em; line-height: 1.5; }
        .container { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
      </style>
    </head>
    <body>
      <div class="container">
        <h1>Just a quick update window</h1>
        <p><strong>YOUR-SITE</strong> is undergoing a brief 30-second system refresh.</p>
        <p>Grab a quick sip of your drink—this page will automatically refresh as soon as we are back online.</p>
      </div>
      <script>
        // Automatically check if the site is back up every 10 seconds
        setInterval(function() {
          window.location.reload();
        }, 10000);
      </script>
    </body>
    </html>
  `;

  return new Response(html, {
    status: 503, // 503 is best for SEO so Google doesn't penalize you for downtime
    headers: {
      "Content-Type": "text/html;charset=UTF-8",
      "Retry-After": "30"
    }
  });
}

يجب أن يبدو شيئاً ما كهذا. انقر على نشر (deploy) لحفظه:

الخطوة 2: إضافة المسار

الآن انتقل إلى صفحة مسارات عامل Cloudflare وانقر على زر add route لإظهار نافذة المسار الجديد، املأ مسار النطاق واختر صفحة العامل التي أنشأتها للتو، ثم انقر على حفظ:

الخطوة 3: تشغيل التحديثات أو إعادة البناء

الآن، عندما تتصل بخادمك عبر SSH وتشغل تحديثات النظام أو تقوم بإعادة البناء، بدلاً من ظهور صفحة توقف الموقع أو صفحة خطأ، ستظهر هذه الصفحة عندما يحدث التوقف فعلياً (أستخدم 30 ثانية في موقعي لأن هذا هو الحد الأقصى لموقعاتي).

أعتمد عادةً على إضافة وحذف مسار عامل Cloudflare الخاص بي كلما قمت بالصيانة، لكن بعض الأشخاص يفضلون تركه هناك طوال الوقت (أترك الكود الفعلي للصفحة، لكنني أضيف وأزيل المسار فقط).

أعتقد أن هذا كل شيء.

اختياري: تشغيل التحديثات باستخدام نص برمجي وجدولة

أستخدم أيضاً نص برمجي Shell Unix على خادمي لتشغيل تحديث خاص بالحاويات المزدوجة، الذي أنشأته على النحو التالي:

cat << 'EOF' > /root/update-web.sh
#!/bin/bash
cd /var/discourse
echo "➡️ Pulling latest Discourse docker scripts..."
git pull

echo "➡️ Bootstrapping new web container in the background (takes ~8 mins)..."
./launcher bootstrap web_only

if [ $? -eq 0 ]; then
    echo "✅ Bootstrap successful! Swapping containers..."
    ./launcher destroy web_only && ./launcher start web_only
    echo "🚀 Done! Site updated with almost zero downtime."
else
    echo "❌ Bootstrap failed! Aborting swap to keep current site online."
fi
EOF

chmod +x /root/update-web.sh

ثم أشغله في موجه root على خادمي باستخدام الأمر ./update-web.sh.


:warning: تعديل: لا تتبع الخطوات أدناه إلا إذا كان لديك حساب مدفوع من Cloudflare.

يمكنك أتمتته لوقت محدد، مثل الساعة 1 صباحاً يوم الأحد بتوقيتك المحلي باستخدام مهمة cron. بالنسبة لي، 1:00 صباحاً محلياً هي 8:00 صباحاً بتوقيت UTC، (يمكنك معرفة التاريخ والتوقيت UTC لخادمك عن طريق كتابة date في موجه الأوامر أثناء الاتصال عبر SSH).

لذا:

شغل هذا الأمر لفتح جدولة المهام في خادمك:

crontab -e

(إذا طلب منك اختيار محرر، اختر المحرر المفضل لديك، 1 لـ nano هو الأرجح الأسهل)

أنتقل إلى أسفل التعليقات وألصق هذا:

0 8 * * 0 /root/update-web.sh >> /var/log/discourse-update.log 2>&1

(وهو يعني تشغيل ملف /root/update-web.sh في الدقيقة 0، الساعة 8 (بتوقيت UTC)، كل صباح يوم أحد)

ثم احفظ واخرج (إذا كنت تستخدم nano):

  1. Ctrl + O للحفظ.
  2. Enter للتأكيد.
  3. Ctrl + X للخروج.

ثم يمكنني تشغيل cat /var/log/discourse-update.log عندما أستيقظ في صباحات أيام الأحد للتحقق مما إذا كان قد تم تشغيله بشكل صحيح. إذا استخدمت جدولة مهام cron، فستحتاج إلى ترك مسار صفحة العامل.

أعتقد أن هذا كل شيء. أخبرني إذا كان لديك أي أسئلة، هاها. إنه أبسط بكثير مما جعلته يبدو، هاها. :grin:

واو! أنا حقاً أقدر هذا الشرح التفصيلي! :raising_hands:
لقد قمت刚才 بحفظ ردك في ملاحظاتي، لذا عندما أقوم بتثبيت Discourse مرة أخرى قريباً، سأعود إليه. سأخبرك بالتأكيد كيف سارت الأمور، حتى لو استغرق الأمر بعض الوقت حتى أقوم بتثبيته. أنا أنهي بعض الأمور المتعلقة بالبرمجة في الوقت الحالي، وسأركز على Discourse مرة أخرى بعد ذلك.

وأوافق على أن صفحة “خادم الويب متوقف” قبيحة، وبالنسبة للمستخدمين غير المتمرسين، هذه الرسالة لا تعني الكثير. وجود صفحة صيانة بسيطة مع رسالة مخصصة، هو دائماً أفضل، حتى لو كان ذلك يتطلب بعض الجهد في الإعداد.

مرة أخرى، شكراً جزيلاً لك جداً على تخصيص الوقت لمشاركة هذا. آمل أن يجد آخرون هذا مفيداً :slight_smile:

وهنا تكمن المشكلة.

إنه ليس تغييراً بسيطاً، كما أنه يتطلب بنية تحتية إضافية تحتاج إلى الاهتمام والصيانة، وفي رأيي الشخصي، لا تستحق العناء إطلاقاً لتجنب بضع ثوانٍ من توقف الخدمة.

أفهم ما تقصد، لكن هذا مجرد حالة واحدة. ماذا لو حدث خلل حقيقي وتطلبت إصلاحه أكثر من بضع ثوانٍ؟

أيضًا، كيف تحصل على بضع ثوانٍ من وقت التوقف بينما كنت أرى حوالي 20 دقيقة، بعد تثبيت الإضافات؟

لأنه في إعداد الحاويتين (المشار إليه في كل من منشورينا ويعتبر اعتمادًا غير قابل للتفاوض)، تقوم بتهيئة الإصدار الجديد باستخدام الأمر ./launcher bootstrap web_only (حيث يظل موقعك يعمل بنسبة 100% خلال هذه العملية)، ثم تقوم ببساطة بتدمير الحاوية القديمة وإطلاق الحاوية الجديدة التي تم بناؤها بالفعل فورًا (وهو ما يستغرق بضع ثوانٍ فقط).

أوه، حسناً، هذا لا يزال يتعلق بإعداد الحاويات الثنائية. ظننت أنك تقول إن بناء إعداد الحاويات الثنائية بالكامل لا يستحق الجهد. ما تقوله هو أن العمل الإضافي الخاص بصفحة الصيانة هو ما لا يستحق الجهد، أليس كذلك؟

شخصياً، نعم.

إذا كنت تريد ضمانات إضافية للمشاهدين عبر الويب الذين يظهر لديهم تنقل جديد خلال الـ 30 إلى 60 ثانية، فإن صفحة الصيانة معقولة.

يجب عليك الموازنة بين فائدة ذلك والوقت اللازم لصيانة البنية التحتية المحيطة به.

الآن فهمت. شكراً.

إذن، السؤال الآن هو: مع وجود حاويتين، لا تزال فترة الـ20 دقيقة تقريباً قائمة، والفرق الوحيد هو أنني يمكنني تركها تعمل على إحدى الحاويتين، تلك التي ليست نشطة، وعندما تكون جاهزة، أقوم بالتبديل. هل هذا هو كيفية عملها؟

نعم، لا يزال الأمر يستغرق بعض الوقت لبناء الحاوية. ولعلمك، يجب أن تتأكد من أن خادمك قوي بما يكفي للسماح بحدوث هذه العملية بالتوازي مع خدمة مجتمعك بشكل طبيعي (والأهم من ذلك هو ضمان وجود ذاكرة كافية في البداية - لذا من المهم جداً التأكد من وجود مساحة SWAP كافية). كما أن عملية البناء ستستهلك نواة واحدة على الأقل، لذا فكّر في استخدام خادم يحتوي على نواتين إضافيتين.

الآن كل شيء واضح. شكراً لك.

كنت أستخدم هذا في البداية، لكن يبدو أنه لم يعد متاحاً:

لذا أحتاج الآن إلى الانتقال إلى هذا:

وهو قفزة كبيرة في السعر… :confused: ويبدو أن الخادم أقل فعالية…؟

أوصي باستخدام 4 جيجابايت على الأقل و3 نوى (“vcpu”) لهذا النوع من الإعدادات …

للمرجع، كما طُرح في موضوع آخر، الإجابة (تعديل: خاطئة): Any cheaper alternatives to Hetzner? - #2 by Canapin

هذا هو الوحيد الذي يطابق ذلك… ما الفرق في السعر…

image

أعتقد أنني سأضطر الآن إلى بنائه باستخدام حاوية واحدة، وعندما يحين الوقت (:money_bag:)، سأقوم بالترقية.

شكراً لك على المعلومات، روبرت!

أنا لا أوافق وأعتقد أنها تستحق صفحة الصيانة. في تجربتي، عندما يرى الأشخاص صفحة خطأ Discourse، فإن أول شيء يفعلونه هو الضغط على زر التحديث، وعندها سيرون صفحة الصيانة المؤقتة التي ستقوم تلقائيًا بإعادة تحميل الموقع عند اكتمال تبديل الحاوية. لا يتطلب الأمر الكثير من الجهد لإعدادها، وعليك القيام بذلك مرة واحدة فقط. أثناء إعادة البناء باستخدام تكوين الحاويات المزدوجة، يحدث جزء التمهيد في الخلفية ويمكن للمستخدمين الاستمرار في استخدام الموقع؛ إن تبديل الحاوية هو ما يسبب انقطاع الخدمة المؤقت (على عكس تكوين الحاوية المفرد القياسي).

تكلفة الخادم واختياره أمر مختلف تمامًا وينبغي أن يكون في موضوع منفصل آخر.

أعتقد أنني الآن في المنتصف. أفهم ما تقصد، وكذلك @merefield. إنها لمسة لطيفة أن يكون الأمر كذلك، وإذا تم ضبطه مرة واحدة فقط، فلا أعتقد أن الأمر كبير؟

في الوقت نفسه، إذا استغرق الأمر حقًا ما يصل إلى 60 ثانية، في أسوأ سيناريو، فإن الجميع لن يزور الموقع في الثانية صفر بالتحديد ويضطر للانتظار 60 ثانية. سيرى بعض الأشخاص الصفحة غير الجميلة لمدة 5 ثوانٍ، والبعض الآخر 20، والبعض الآخر 60. قد لا يرى بعض الأشخاص ذلك على الإطلاق (أعتقد؟)، على سبيل المثال إذا كانوا يقرأون ردًا فقط أو يكتبون واحدًا، فقد يحدث هذا التبديل قبل أن يضغطوا على إرسال أو قبل أن يتوقفوا عن قراءة الموضوع ويضغطوا على رد (أو يزوروا صفحة أخرى).

مشكلتي مع مسار nginx كانت تتعلق أكثر بأمر الـ 20 دقيقة في إعداد الحاوية الواحدة. مع خيار وجود حاويتين والانتقال من 20 دقيقة إلى 60 ثانية كحد أقصى، أتساءل عما إذا كان ذلك ذا صلة حقًا؟ خاصة إذا كان بإمكاني إضافة إعلان في الأعلى يقول إن الأمور ستتوقف لبضع ثوانٍ فقط، في وقت منخفض الحركة، فلن يكون ذلك مشكلة كبيرة؟

يجب أن أجلس وأفكر في الأمر. سيكون إعداد الحاويتين بالتأكيد شيئًا لتنفيذه، إذا وجدت عرضًا جيدًا للسيرفر.

هل يمكنك توضيح هذا الأمر بطريقة يفهمها شخص مبتدئ مثلي؟ لا أزال غير مألوف مع العمال (Workers)…

لماذا تقوم بإضافة وحذف صفحة مسار العمال إذا كان تركها لا يمثل مشكلة؟ إذًا، إذا أضفت صفحة الصيانة، هل يمكنني حقًا إعدادها مرة واحدة، ومن تلك اللحظة فصاعدًا، أقوم دائمًا بالاتصال بخادمي عبر SSH باستخدام المحطة الطرفية (Terminal) وأقوم بكل شيء هناك كما أفعل مع حاوية واحدة، دون الحاجة مطلقًا إلى زيارة Cloudflare؟

ذكر @merefield أن هذا (صفحة الصيانة، العمال، وما إلى ذلك) هو أيضًا شيء يحتاج إلى صيانة، لذا أتساءل عما إذا كان هذا حقًا شيئًا تُضبطه وتنساه، أم أن هناك شيئًا يحتاج إلى القيام به من وقت لآخر؟