لماذا معمارية الأحداث (Event-driven) بلغة Go هي الحزام الأسود الجديد في التطوير؟
\n\nتخيل أوركسترا حيث يعزف كل موسيقي دوره الخاص دون انتظار قائد الفرقة، ومع ذلك يخلقون سيمفونية مثالية. هذا هو بالضبط ما تفعله معمارية الأحداث (Event-driven) بلغة Go — كل خدمة تعيش حياتها الخاصة، وتتفاعل مع الأحداث وتنتج أحداثًا جديدة، دون حظر التدفق العام.
\n\nفي عالم يطلب فيه المستخدمون استجابة فورية، وتعالج فيه الأنظمة ملايين الطلبات في الثانية، تبدأ REST APIs المتزامنة في "الاختناق". Go مع goroutines خفيفة الوزن والدعم الأصلي للتوازي يصبح اللغة المثالية لبناء أنظمة تفاعلية. ولكن كيف نحول فوضى الاستدعاءات غير المتزامنة إلى معمارية منظمة؟ دعنا نكتشف ذلك.
\n\nما هي معمارية الأحداث (EDA) ولماذا Go؟
\n\nمعمارية الأحداث (Event-driven) بلغة Go هي نموذج حيث تتواصل مكونات النظام من خلال الأحداث بدلاً من الاستدعاءات المباشرة. بدلاً من أن تنتظر الخدمة A ردًا من الخدمة B، تقوم ببساطة بنشر رسالة في الوسيط، وتلتقطها B عندما تكون جاهزة.
\n\nلماذا Go مثالية لـ EDA؟
\n- \n
- Goroutines — "خيوط" رخيصة الثمن لمعالجة الأحداث المتوازية (يمكن تشغيل مليون منها دون مشاكل) \n
- القنوات (Channels) — آلية مدمجة لنقل الأحداث بين goroutines \n
- الترجمة السريعة — التكرارات في الميكروسيرفيسات تصبح خاطفة \n
- البساطة — "سحر" أقل، تحكم أكثر \n
بناء أول نظام قائم على الأحداث بلغة Go: من البسيط إلى المعقد
\n\nالمستوى 1: الأحداث الداخلية عبر القنوات
\nلنبدأ بالأساسيات. تخيل أننا نكتب نظام مراقبة للخادم. كل حدث (انخفاض الذاكرة، ارتفاع وحدة المعالجة المركزية) يجب معالجته بشكل غير متزامن.
\n\npackage main\n\nimport (\n "fmt"\n "math/rand"\n "time"\n)\n\ntype Event struct {\n Type string\n Payload interface{}\n}\n\nfunc main() {\n // إنشاء قناة للأحداث\n eventChannel := make(chan Event, 100)\n \n // المنتج: توليد الأحداث\n go func() {\n for {\n time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)\n event := Event{\n Type: "system.memory.alert",\n Payload: map[string]interface{}{\n "usage_pct": rand.Float64() * 100,\n "timestamp": time.Now(),\n },\n }\n eventChannel <- event\n }\n }()\n \n // المستهلك: معالجة الأحداث\n go func() {\n for event := range eventChannel {\n fmt.Printf("تم استلام الحدث: %s\\n", event.Type)\n processEvent(event)\n }\n }()\n \n time.Sleep(5 * time.Second)\n}\n\nfunc processEvent(e Event) {\n // محاكاة المعالجة\n time.Sleep(200 * time.Millisecond)\n fmt.Printf("تمت المعالجة: %v\\n", e.Payload)\n}\n\nهذا هو الأساس، ولكن للإنتاج نحتاج إلى شيء أكبر. عندما يتجاوز عدد الخدمات العشرة، تظهر وسطاء الرسائل على المسرح.
\n\nالمستوى 2: معمارية الأحداث بلغة Go مع NATS
\nNATS هو وسيط خفيف الوزن يتوافق بشكل مثالي مع Go. إنه أسرع من RabbitMQ وأبسط من Kafka.
\n\npackage main\n\nimport (\n "log"\n "time"\n "github.com/nats-io/nats.go"\n)\n\ntype OrderEvent struct {\n OrderID string `json:"order_id"`\n Status string `json:"status"`\n Amount float64 `json:"amount"`\n Time time.Time `json:"time"`\n}\n\nfunc main() {\n // الاتصال بـ NATS\n nc, err := nats.Connect(nats.DefaultURL)\n if err != nil {\n log.Fatal(err)\n }\n defer nc.Close()\n \n // نشر الحدث (المنتج)\n event := OrderEvent{\n OrderID: "ORD-12345",\n Status: "created",\n Amount: 299.99,\n Time: time.Now(),\n }\n \n data, _ := json.Marshal(event)\n