0%
الإطلاق في بيئة الإنتاج

الإطلاق في بيئة الإنتاج

ما يفصل بين خادم يعمل وخدمة يمكن تشغيلها وصيانتها.

10-15 دقيقة

الإطلاق في بيئة الإنتاج

مع كل عملية نشر، يرى عدد قليل من المستخدمين خطأ في الشبكة. ليس كافيًا لإطلاق تنبيه، لكنه كافٍ لتوليد تذاكر دعم. السبب ليس في منطق عملك: المُنسِّق (orchestrator) يرسل SIGTERM إلى العملية، فتنتهي Node فورًا، وتُقطع كل الطلبات قيد المعالجة في منتصفها، بما فيها تلك التي كتبت بياناتها في قاعدة البيانات ولم تؤكد النتيجة للعميل قط. خمسة أسطر تكفي لإزالة هذا العَرَض كليًا، ومعظم الخدمات لا تتضمنها.

الفجوة الثانية بين «إنها تعمل» و«يمكن تشغيلها وصيانتها» تتعلق بالمراقبة (observability). الخدمة التي لا تتيح فحص صحة منفصلًا عن فحص الجاهزية تتلقى حركة المرور قبل أن تصبح جاهزة. والخدمة التي تسجّل أحداثها بجمل حرة لا تتيح العثور على طلبات مستخدم بعينه أثناء حادثة. والخدمة التي تُشغّل صورة الحاوية الخاصة بها عمليتها بصلاحيات root تمنح أي تنفيذ لشيفرة عشوائية كامل الصلاحيات داخل الحاوية. يعالج هذا الدرس الأخير هذه النقاط بالترتيب الذي ستكلّفك به أكثر.

إيقاف سلس

الهدف: التوقف عن قبول اتصالات جديدة، وترك الطلبات الجارية تنتهي، وإغلاق الموارد، ثم الخروج.

// src/serveur.js
import { creerApp } from './app.js';
import { config } from './config.js';
import { pool } from './bd/pool.js';
import { logger } from './intergiciels/journalisation.js';

const app = creerApp();
const serveur = app.listen(config.port, () => {
  logger.info({ port: config.port }, 'API démarrée');
});

let arretEnCours = false;

async function arreterProprement(signal) {
  if (arretEnCours) return;
  arretEnCours = true;
  logger.info({ signal }, 'Arrêt demandé');

  // شبكة أمان: لا نبقى عالقين إلى ما لا نهاية.
  const minuterie = setTimeout(() => {
    logger.error('Arrêt forcé après expiration du délai');
    process.exit(1);
  }, 10_000);
  minuterie.unref();

  serveur.close(async (err) => {
    if (err) logger.error({ err }, 'Erreur à la fermeture du serveur HTTP');
    try {
      await pool.end();
      logger.info('Arrêt terminé');
      process.exit(err ? 1 : 0);
    } catch (e) {
      logger.error({ err: e }, 'Erreur à la fermeture du groupe de connexions');
      process.exit(1);
    }
  });
}

process.on('SIGTERM', () => arreterProprement('SIGTERM'));
process.on('SIGINT', () => arreterProprement('SIGINT'));

التعليقات

التعليقات مدعومة عبر GitHub Discussions

سجّل الدخول باستخدام GitHub للمشاركة في النقاش

تم نسخ الرابط!