تخطَّ إلى المحتوى

🐹 شرح Go

حزمة context: الإلغاء والمُهل الزمنية

الدرس 26 من 28· ⏱ 2 دقائق قراءة

لماذا نحتاج context؟

خادم يشغّل goroutine لكل طلب — لو العميل قطع الاتصال أو تجاوز الطلب مهلة معقولة، لازم طريقة موحّدة توقف كل العمل الجاري (استعلامات قاعدة البيانات، طلبات خارجية...) بدل ما تستمر بلا فائدة. هذا بالضبط دور context.Context.

import "context"

نقطة البداية

ctx := context.Background()   // جذر فارغ، لا يُلغى أبدًا — لبداية main أو الاختبارات
ctx := context.TODO()         // لما لم تحدّد context المناسب بعد

الإلغاء اليدوي — WithCancel

ctx, cancel := context.WithCancel(context.Background())
defer cancel()   // حرّر الموارد دائمًا حتى لو انتهى العمل طبيعيًا

go worker(ctx)

func worker(ctx context.Context) {
  for {
    select {
    case <-ctx.Done():
      fmt.Println("توقّفت:", ctx.Err())
      return
    default:
      // عمل مستمر
    }
  }
}

استدعاء cancel() يغلق قناة Done()، فكل مكان يستمع لها يتوقّف فورًا.

المهلة الزمنية — WithTimeout

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

select {
case <-ctx.Done():
  fmt.Println("انتهت المهلة:", ctx.Err())   // context.DeadlineExceeded
case result := <-doWork(ctx):
  fmt.Println(result)
}

WithTimeout اختصار لـ WithDeadline بوقت نسبي بدل وقت مطلق.

تمرير قيم — WithValue

type key string
const userIDKey key = "userID"

ctx := context.WithValue(context.Background(), userIDKey, 42)
userID := ctx.Value(userIDKey).(int)

💡 استخدم WithValue فقط لبيانات مرتبطة بالطلب (معرّف مستخدم، رقم تتبّع...)، لا كبديل عن معاملات الدالة العادية — كثرة القيم المخفية بالـ context تصعّب قراءة الكود.

context في خادم HTTP

كل *http.Request يحمل context جاهزًا يُلغى تلقائيًا عند قطع العميل الاتصال:

func handler(w http.ResponseWriter, r *http.Request) {
  ctx := r.Context()
  select {
  case <-ctx.Done():
    return   // العميل غادر، لا داعي لإكمال العمل
  case <-time.After(3 * time.Second):
    fmt.Fprintln(w, "انتهيت")
  }
}

القاعدة الذهبية

  • context.Context أول معامل بالدالة دائمًا: func DoSomething(ctx context.Context, arg Arg) error.
  • لا تخزّن context داخل struct — مرّره صراحةً.
  • لا تمرّر nil — استخدم context.TODO() عند التردّد.
  • استدعِ cancel() دائمًا (عادةً عبر defer) لتحرّر الموارد فور انتهاء العمل.

🎯 التالي: الملفات وسطر الأوامر.

شرح حزمة context: الإلغاء والمُهل الزمنية — Go بالعربي
حزمة context: الإلغاء والمُهل الزمنيةGo بالعربي · The Code Fix

📚 لمزيد من التعمّق في Go، راجِع التوثيق الرسمي لـ Go.

هل كان هذا الدرس مفيدًا؟