لماذا بنية الحدثية؟
تواجه الشركات السورية تحديات متعلقة باتصال الشبكة المتقطع، والأحمال المتقلبة، والحاجة إلى ربط أنظمة ERP القديمة مع الخدمات الرقمية الحديثة. تسمح بنية الحدثية (EDA) بفصل المنتجين عن المستهلكين، مما يمكّن كل مكوّن من التطور بشكل مستقل، والتوسع عند الحاجة، والبقاء فعالًا حتى أثناء الانقطاعات.
الفوائد الأساسية في السياق السوري:
- المرونة: تُحفظ الأحداث في وسيط الرسائل، لذا يمكن لخدمة المستهلك إعادة التشغيل دون فقدان البيانات.
- القابلية للتوسع: يمكن إضافة مؤشرات مستهلكة إضافية خلال فترات الذروة (مثل موسم التسوق) دون تعديل المنتج.
- المرونة: دمج خدمات جديدة – دفعات هاتفية، تحليلات ذكاء اصطناعي، مستشعرات إنترنت الأشياء – عن طريق الاشتراك في الأحداث ذات الصلة فقط.
المكوّنات الأساسية
- منتجي الأحداث – أي خدمة تنشر حدثًا Domain مثل
order.created. - وسيط الرسائل – مخزن دائم (RabbitMQ أو Apache Kafka أو AWS SQS) يضمن تسليم الأحداث بالترتيب.
- مستقبلو الأحداث – خدمات مصغرة أو وظائف تتفاعل مع الأحداث، تحول البيانات أو تُطلق عمليات فرعية.
- سجل المخطط (اختياري) – عقد مشترك (Avro/JSON‑Schema) لضمان شكل الحدث.
اختيار الوسيط المناسب للسوق السوري
| الوسيط | يدعم تشغيل محلي | مدعوم سحابي (Azure/AWS) | تكلفة التشغيل | |--------|----------------|--------------------------|----------------| | RabbitMQ | ✅ (Docker) | ✅ (جسر Azure Service Bus) | منخفض | | Apache Kafka | ✅ (Confluent) | ✅ (Azure Event Hubs) | متوسط | | NATS | ✅ (خفيف) | ❌ | منخفض جداً |
معظم الشركات الصغيرة والمتوسطة ستجد RabbitMQ الأسهل؛ يمكن تشغيله داخل حاوية Docker، يدعم بروتوكول AMQP المتوافق مع معظم المكتبات، ويوفر واجهة إدارة رسومية.
مثال تنفيذي (Node.js + RabbitMQ)
> ملاحظة: الشيفرة توضيحية؛ في بيئة الإنتاج أضف معالجة الأخطاء، وإعادة المحاولة، والتحقق من عدم التكرار.
// producer.js – نشر حدث OrderCreated
const amqp = require('amqplib');
const ORDER_EXCHANGE = 'orders';
async function publishOrder(order) {
const conn = await amqp.connect('amqp://guest:guest@localhost:5672');
const ch = await conn.createChannel();
await ch.assertExchange(ORDER_EXCHANGE, 'topic', { durable: true });
const event = { type: 'order.created', payload: order, ts: Date.now() };
ch.publish(ORDER_EXCHANGE, 'order.created', Buffer.from(JSON.stringify(event)));
console.log('Published order.created');
await ch.close();
await conn.close();
}
publishOrder({ id: 123, amount: 2500, currency: 'SYP' });
// consumer.js – معالجة OrderCreated وتحديث ERP
const amqp = require('amqplib');
const ORDER_EXCHANGE = 'orders';
async function startConsumer() {
const conn = await amqp.connect('amqp://guest:guest@localhost:5672');
const ch = await conn.createChannel();
await ch.assertExchange(ORDER_EXCHANGE, 'topic', { durable: true });
const q = await ch.assertQueue('', { exclusive: true });
await ch.bindQueue(q.queue, ORDER_EXCHANGE, 'order.created');
console.log('Waiting for order.created events...');
ch.consume(q.queue, async (msg) => {
const event = JSON.parse(msg.content.toString());
console.log('Received order', event.payload.id);
// TODO: استدعاء API الـ ERP، معالجة الخطأ، تخزين حالة الإقرار
ch.ack(msg);
});
}
startConsumer();
نصائح تشغيلية للنشر في سوريا
- تشغيل الوسيط محليًا (مثلاً على خادم في حلب) لتقليل زمن الاستجابة للأنظمة داخل المؤسسة.
- تفعيل TLS بين الخدمات؛ حتى الشبكات الداخلية يجب أن تكون مشفّرة نظرًا لمعالجة البيانات المالية الحساسة.
- حفظ الرسائل على القرص (
durable: true) لتحمل الانقطاعات الكهربائية التي قد تحدث في بعض المناطق. - استخدام قوائم انتظار الرسائل الميتة (dead‑letter) للأحداث غير الصالحة؛ لتجنب إيقاف المستهلك بسبب رسالة واحدة معطوبة.
- مراقبة بسيطة باستخدام Prometheus + Grafana؛ وهناك مستوردات جاهزة لـ RabbitMQ.
أنماط التوسع
- توسيع المستهلكين أفقياً – نشر عدة نسخ خلف موزّع تحميل؛ سيقوم الوسيط بتوزيع الرسائل بالتساوي.
- تقسيم حسب نوع الحدث – تخصيص تبادل (exchange) مستقل للمدفوعات الحرجة لتفادي التداخل.
- تخزين الأحداث (Event Sourcing) – حفظ كل حدث بسجل غير قابل للتغيير (Kafka) لإعادة بناء الحالة وتحليل البيانات.
اعتبارات الأمان
- مصادقة المنتجين/المستهلكين عبر اسم مستخدم/كلمة مرور أو شهادات TLS.
- منح أقل الصلاحيات: يجب أن تشترك خدمة المدفوعات فقط في مواضيع
payment.*. - تحقق من صحة الحمولة باستخدام مخطط JSON قبل المعالجة.
تواصل معنا للبدء في تصميم بنية حدثية تلائم متطلبات عملك في سوريا.