نشر خدمات Swift بدون توقف: كيفية التحديث دون توقف

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا النشر بدون توقف ليس رفاهية بل ضرورة لمطور Swift

\n

تخيل: خدمة Swift الخاصة بك على Vapor تعالج آلاف الطلبات في الثانية. تقوم بإصدار ميزة جديدة - ويحصل المستخدمون على 502 Bad Gateway، وفي السجلات - SIGTERM واتصالات مقطوعة. مألوف؟ إذا كنت تكتب بلغة Swift للخادم الخلفي، فستواجه عاجلاً أم آجلاً مشكلة: كيف تحديث الخدمة دون فقدان أي طلب.

\n

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

\n\n

ما هو النشر بدون توقف ولماذا هو مهم لمشاريع Swift

\n

النشر بدون توقف (Zero-downtime deployment) هو عندما تقوم بتحديث التطبيق ولا يلاحظ المستخدمون أي جزء من الألف من الثانية من التوقف. بالنسبة لخدمات Swift، هذا مهم بشكل خاص لأن:

\n
    \n
  • العملاء لا يتحملون الأخطاء - الطلب المقطوع = بيانات أو أموال مفقودة.
  • \n
  • خوادم Swift غالباً ما تعمل تحت حمولة عالية (التكنولوجيا المالية، الدردشات، API الوقت الفعلي).
  • \n
  • إعادة تشغيل الملف الثنائي قد تستغرق ثوانٍ - وهذا وقت طويل بالنسبة لاتصال نشط.
  • \n
\n

النهج الكلاسيكي - قتل العملية القديمة وتشغيل عملية جديدة - لا يعمل. يجب على تطبيق Swift على Vapor أو Hummingbird إنهاء معالجة الطلبات الحالية بسلاسة، ثم إفساح المجال لمثيل جديد. هذا هو موضوع كل الكود التالي.

\n\n

الخطوة 1. الإيقاف السلس في Swift: كتابة إنهاء صحيح

\n

اللبنة الأولى للنشر بدون توقف هي الإيقاف السلس. يجب أن تكون خدمة Swift الخاصة بك قادرة على التقاط إشارة SIGTERM وعدم قطع الاتصالات في منتصف الطريق. Vapor 4+ يفعل ذلك بالفعل بشكل افتراضي، لكن دعنا نتحقق، وإذا لزم الأمر، نضيف منطقاً مخصصاً.

\n\n

الإعداد الأساسي لـ Vapor للإيقاف السلس

\n
import Vapor\n\nlet app = Application()\n\n// تسجيل معالج الإشارة\napp.lifecycle.use(ShutdownSignalHandler())\n\n// كود Vapor القياسي\napp.get("health") { req in\n    return "OK"\n}\n\ntry app.run()\n
\n

لكن ماذا لو كنت بحاجة إلى انتظار اكتمال المهام الطويلة؟ على سبيل المثال، معالجة الملفات أو إرسال البريد الإلكتروني. دعنا نضيف ShutdownSignalHandler مخصصاً:

\n\n
import Vapor\nimport NIOCore\n\nfinal class ShutdownSignalHandler: LifecycleHandler {\n    private var runningTasks: [EventLoopFuture<Void>] = []\n    \n    func willBoot(_ app: Application) throws {\n        // الاشتراك في SIGTERM\n        app.running?.onStop = {\n            print("⏳ تم استلام إشارة الإيقاف. إنهاء المهام النشطة...")\n            return self.runningTasks.flatten(on: app.eventLoopGroup.next())\n        }\n    }\n    \n    func registerTask(_ task: EventLoopFuture<Void>) {\n        runningTasks.append(task)\n    }\n}\n
\n

الآن، عندما تصل SIGTERM، سينتظر الخادم اكتمال جميع المهام المسجلة. هذا أمر بالغ الأهمية للنشر بدون توقف لخدمات Swift: العملية القديمة لن تقتل الطلبات التي بدأت بالفعل في معالجتها.

\n\n

التحقق في وحدة التحكم

\n

قم بتشغيل الخادم وأرسل إليه إشارة:

\n
kill -SIGTERM <PID>\n
\n

في السجلات، سترى رسالة حول الإنهاء السلس. إذا كان كل شيء يعمل - انتقل إلى الخطوة التالية.

\n\n

الخطوة 2. النشر الأزرق-الأخضر على Swift: ملفان ثنائيان - بدون توقف

\n

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

\n

الجوهر بسيط: لديك مثيلان لخدمة Swift (أزرق وأخضر). واحد نشط، والثاني في وضع الاستعداد. عندما تقوم بتحديث الكود، فإنك:

\n
    \n

المدونات

توصيات الكتب