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

Event Sourcing

Event Sourcing — تخزين الأحداث بدل الحالة Event Sourcing

بدل تخزين الحالة الحالية فقط، يُخزَّن كل تغيير كحدث مستقل، والحالة الحالية تُشتق بإعادة تشغيل كل الأحداث بالترتيب.

التخزين التقليدي يحتفظ بآخر حالة فقط — تحديث سجل يمحو قيمته السابقة. Event Sourcing يخزّن كل تغيير كحدث غير قابل للتعديل (Immutable) في سجل مرتب زمنياً، والحالة الحالية لأي كيان هي نتيجة تطبيق كل أحداثه بالترتيب من البداية.

هذا يمنح سجلاً كاملاً وقابلاً للتدقيق لكل ما حدث (مفيد جداً للمعاملات المالية والامتثال)، ويسمح ببناء نماذج قراءة جديدة لاحقاً بإعادة تشغيل الأحداث القديمة، لكنه يضيف تعقيداً في الاستعلام المباشر عن الحالة الحالية.

الصياغة

events = [Created, ItemAdded, Shipped, ...]
currentState = events.reduce(apply, initialState)

📄 مثال

// سجل الأحداث بدل تعديل السجل مباشرة
await eventStore.append(orderId, { type: 'OrderCreated', total: 0 });
await eventStore.append(orderId, { type: 'ItemAdded', price: 50 });
await eventStore.append(orderId, { type: 'ItemAdded', price: 30 });

// الحالة الحالية = نتيجة تطبيق كل الأحداث بالترتيب
const state = (await eventStore.getEvents(orderId)).reduce(applyEvent, {});
// state.total === 80

أهم النقاط

العنصرالوظيفة
الأحداث غير قابلة للتعديللا يُحذف أو يُعدَّل حدث سابق، فقط تُضاف أحداث جديدة
سجل تدقيق كاملكل تغيير محفوظ بترتيبه الزمني، لا فقط النتيجة النهائية

💡 نصائح عملية

  • استخدم Snapshots دورية (حفظ الحالة كل N حدث) لتفادي إعادة تشغيل آلاف الأحداث في كل قراءة
  • غالباً يُقترن بـ CQRS — الأحداث تُبنى منها نماذج قراءة مُجمَّعة

⚠️ أخطاء شائعة

  • بناء استعلامات مباشرة معقدة فوق سجل الأحداث الخام بدل بناء نموذج قراءة منفصل
  • تطبيقه على كل كيان في النظام دون تقييم هل سجل التدقيق الكامل يستحق التعقيد الإضافي فعلاً

خصائص ذات صلة

🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار MICROSERVICES الكامل بالعربي.