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

🏗️ شرح المايكروسيرفيس (Microservices)

العمارة المعتمدة على الأحداث (Event-Driven)

الدرس 9 من 25· ⏱ 2 دقائق قراءة

ما هي العمارة Event-Driven؟

النظام يتفاعل مع الأحداث (Events) — كل حدث يمثل تغييراً في حالة النظام. الخدمات تنشر الأحداث وتستمع إليها دون معرفة مباشرة ببعضها.

المكونات الأساسية

Event-Driven Architecture:
  Producer: تنشر الأحداث
  Event Bus: وسيط (RabbitMQ, Kafka)
  Consumer: تستمع وتتفاعل
  Event Store: تخزين الأحداث (اختياري)

مثال عملي

import { OrderRepositoryProtocol, OrderAlreadyCompletedError } from './lib/base_repository';

// Service Layer — لا يستدعي db.orders.create() مباشرة
class OrderEventService {
  constructor(private readonly orderRepo: OrderRepositoryProtocol) {}

  async createOrder(orderData: OrderData): Promise<OrderEntity> {
    const existing = await this.orderRepo.findById(orderData.id);
    if (existing) throw new OrderAlreadyCompletedError(orderData.id);

    const order = await this.orderRepo.save({
      id: orderData.id,
      userId: orderData.userId,
      items: orderData.items,
      total: orderData.total,
      status: 'CREATED',
      createdAt: new Date(),
    });

    await eventBus.publish('order.created', {
      orderId: order.id,
      userId: order.userId,
      amount: order.total,
      timestamp: new Date(),
    });

    return order;
  }
}
// خدمة المخزون — تستمع لحدث إنشاء طلب
eventBus.subscribe('order.created', async (event) => {
  console.log(`تجهيز الطلب ${event.orderId} للمستخدم ${event.userId}`);

  // تحديث المخزون
  await inventoryService.reserveItems(event.orderId, event.items);
});
// خدمة الإشعارات — تستمع لنفس الحدث
eventBus.subscribe('order.created', async (event) => {
  await notificationService.sendEmail(event.userId, {
    subject: 'تم تأكيد طلبك',
    orderId: event.orderId,
  });
});

Event Sourcing

تخزين كل تغييرات الحالة كسلسلة من الأحداث بدلاً من الحالة الحالية فقط.

import { OrderAlreadyCompletedError } from './lib/base_repository';

class OrderAggregate {
  private id: string = '';
  private status: string = 'PENDING';
  private readonly events: DomainEvent[] = [];

  applyEvent(event: DomainEvent): void {
    switch (event.type) {
      case 'ORDER_CREATED':
        this.id = event.data.orderId;
        this.status = 'CREATED';
        break;
      case 'ORDER_SHIPPED':
        if (this.status !== 'CREATED') {
          throw new OrderAlreadyCompletedError(this.id);
        }
        this.status = 'SHIPPED';
        break;
      case 'ORDER_DELIVERED':
        if (this.status !== 'SHIPPED') {
          throw new Error('Order must be SHIPPED before DELIVERED');
        }
        this.status = 'DELIVERED';
        break;
    }
    this.events.push(event);
  }

  getState(): { id: string; status: string } {
    return { id: this.id, status: this.status };
  }

  getUncommittedEvents(): readonly DomainEvent[] {
    return this.events;
  }
}

أنواع الأحداث

// حدث commands (طلب تنفيذ إجراء)
{ type: 'RESERVE_INVENTORY', data: { orderId: '123', items: [...] } }

// حدث domain event (تم إنجاز شيء)
{ type: 'ORDER_CONFIRMED', data: { orderId: '123' } }

// حدث notification (إعلام فقط)
{ type: 'USER_NOTIFIED', data: { userId: '456', message: 'تم التأكيد' } }

فوائد Event-Driven

  • فصل كامل بين الخدمات
  • قابلية توسع عالية — كل مستمع يعمل بشكل مستقل
  • مرونة — إضافة service جديدة فقط باستمع للحدث
  • سجل كامل للأحداث لأغراض التدقيق

⚠️ العمارة Event-Driven أصعب في التصحيح والتتبع — استخدم Distributed Tracing

🎯 التالي: 09-cqrs

شرح العمارة المعتمدة على الأحداث (Event-Driven) — المايكروسيرفيس (Microservices) بالعربي
العمارة المعتمدة على الأحداث (Event-Driven)المايكروسيرفيس (Microservices) بالعربي · The Code Fix

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