System Design

Event-Driven Architecture

Event-Driven Architecture (EDA) — tizim komponentlari event’lar orqali muloqot qiladi.

Traditional vs Event-Driven

Traditional (Synchronous)

// Order Service
async function createOrder(order) {
  await db.saveOrder(order);
  await inventoryService.decreaseStock(order.items); // Tight coupling
  await emailService.sendReceipt(order.email);
  await analyticsService.track(order);
}

Tight coupling: Har bir service to’g’ridan-to’g’ri chaqiriladi

Event-Driven (Asynchronous)

// Order Service
async function createOrder(order) {
  await db.saveOrder(order);
  await eventBus.publish('order.created', order); // Loose coupling
}

// Other services listen
inventoryService.on('order.created', decreaseStock);
emailService.on('order.created', sendReceipt);
analyticsService.on('order.created', track);

Loose coupling: Services mustaqil

Benefits

1. Scalability

Order Service: 1 instance
Email Service: 10 instances (slow)
Analytics: 5 instances
Each scales independently 

2. Reliability

Email Service down → Order still processed
Event queued → Email sent when service recovers

3. Extensibility

// Add new feature - no code change in Order Service
notificationService.on('order.created', sendPushNotification);

Event Types

1. Domain Events

// Business events
'user.registered'
'order.placed'
'payment.completed'
'product.outOfStock'

2. System Events

// Technical events
'cache.invalidated'
'database.slow'
'service.healthCheck'

3. Integration Events

// External system events
'stripe.payment.succeeded'
'aws.s3.object.created'

Event Structure

{
  id: 'evt_123abc',
  type: 'order.created',
  timestamp: '2024-01-15T10:30:00Z',
  version: 1,
  data: {
    orderId: 'ord_456',
    userId: 'usr_789',
    total: 99.99,
    items: [...]
  },
  metadata: {
    correlationId: 'req_xyz',
    source: 'order-service-v2'
  }
}

Event Sourcing

Store events, not current state:

// Traditional (state-based)
users = { id: 123, balance: 500 }

// Event Sourcing (event-based)
events = [
  { type: 'account.created', balance: 0 },
  { type: 'deposit', amount: 300 },
  { type: 'deposit', amount: 200 }
]

// Rebuild state
balance = events.reduce((sum, e) => sum + (e.amount || 0), 0); // 500

Benefits:

CQRS (Command Query Responsibility Segregation)

Commands (Write)     Queries (Read)
      ↓                   ↑
  Write Model          Read Model
      ↓                   ↑
    Events ─────────────→
// Write Model (normalized)
commands.createOrder(order) → events.orderCreated

// Read Model (denormalized for queries)
events.orderCreated → updateOrderSummaryView

Best Practices

1. Idempotent event handlers

eventBus.on('order.created', async (event) => {
  const processed = await db.exists(`event:${event.id}`);
  if (processed) return; // Skip duplicate
  
  await processOrder(event.data);
  await db.set(`event:${event.id}`, true);
});

2. Event versioning

// v1
{ type: 'user.created', name: 'Ali' }

// v2 (backward compatible)
{ 
  type: 'user.created',
  version: 2,
  firstName: 'Ali',
  lastName: 'Valiyev' // New field
}

3. Correlation ID

// Track request across services
{
  correlationId: 'req_abc123',
  causationId: 'evt_xyz456'
}

Xulosa

Event-Driven:

Patterns:

Keyingi dars: Microservices vs Monolith.