حزمة Go Context
يستخدم معظم مطوري Go context.Context دون فهمه حقاً. تراه في معالجات HTTP، واستدعاءات قواعد البيانات، وطرق SDK. يميل الكثير من المبتدئين إلى تمرير context.Background() في كل مكان.
يتسبب هذا الخطأ في حدوث مشكلات؛ فقد تظل وظيفة Lambda عالقة بعد انتهاء مهلة التنفيذ الخاصة بها، أو قد يستمر استعلام قاعدة البيانات في العمل حتى بعد انقطاع اتصال المستخدم.
تتيح لك Context إرسال إشارات الإلغاء والمواعيد النهائية (deadlines) عبر الكود الخاص بك. وهي تساعدك في الإجابة على ثلاثة أسئلة:
• هل يجب أن تستمر هذه العملية في العمل؟ • متى يجب أن تنتهي هذه العملية؟ • ما هي بيانات الطلب التي تتدفق مع هذا الاستدعاء؟
تحتوي واجهة Context على أربع دوال (methods):
Deadline(): تُرجع الوقت الذي سيتم فيه إلغاء الـ context.Done(): تُرجع قناة (channel) تُغلق عند إلغاء الـ context. استخدمها في جملselectلإيقاف العمل.Err(): تُرجع سبب توقف الـ context (سواء كانDeadlineExceededأوCanceled).Value(): تسترجع البيانات المرتبطة بنطاق الطلب مثلTrace ID.
تعمل Context كشجرة؛ حيث تبدأ بـ context أب (parent) وتنشئ منه سياقات فرعية (children).
سياقات الجذر (Root Contexts):
context.Background(): استخدم هذا في بداية برنامجك.context.TODO(): استخدم هذا كعنصر مؤقت أثناء إعادة هيكلة الكود (refactoring).
السياقات الفرعية (Child Contexts):
context.WithCancel(): تتيح لك إيقاف العمل يدوياً.context.WithTimeout(): توقف العمل بعد مدة زمنية محددة.context.WithDeadline(): توقف العمل في وقت محدد.context.WithValue(): تمرر البيانات الوصفية (metadata) مثل معرفات المستخدمين (User IDs).
قاعدة حاسمة: استدعِ دالة الإلغاء (cancel function) دائماً. استخدم defer cancel() مباشرة بعد إنشاء سياق فرعي. إذا تجاهلت ذلك، فستتسبب في حدوث تسريبات للذاكرة (memory leaks).
أفضل الممارسات:
- مرر الـ context كأول وسيط (argument) للدوال.
- لا تقم بتخزين الـ context داخل الـ structs.
- استخدم
context.WithValueللبيانات الوصفية فقط، وليس للاعتمادات (dependencies) مثل عملاء قواعد البيانات (database clients). - تحقق من
ctx.Err()داخل الحلقات التكرارية الطويلة للخروج مبكراً. - استخدم أنواعاً مخصصة (custom types) لمفاتيح الـ context لتجنب حدوث تضارب (collisions).
عندما يتم إلغاء سياق أب، يتم إلغاء جميع السياقات الفرعية التابعة له تلقائياً. وهذا يسهل إيقاف سلسلة كاملة من العمليات عبر نظامك بالكامل.