VOOZH about

URL: https://dev.to/binadit/event-driven-vs-request-driven-architecture-5an1

⇱ Event-driven vs request-driven architecture - DEV Community


When synchronous chains kill your application performance

Your app handles 10 users perfectly. At 100 users, everything crawls. At 500? Complete system failure.

I've watched countless teams hit this wall. Their request-driven architecture works flawlessly in development, then crumbles under production load. Here's why this happens and how to fix it.

The synchronous bottleneck problem

In request-driven systems, every user action triggers a chain of blocking operations:

User submits order →
 Validate payment (300ms) →
 Check inventory (200ms) →
 Send confirmation email (400ms) →
 Update analytics (150ms) →
 Return response (total: 1050ms)

One slow step kills everything downstream. When your email service takes 3 seconds instead of 400ms, users wait 3.75 seconds for a simple order confirmation.

Under load, this gets exponentially worse. With 200 concurrent orders, you need 200 simultaneous connections to every downstream service. Resources exhaust quickly. Requests pile up. The cascade failure begins.

Event-driven architecture as a solution

Event-driven systems break these synchronous chains by making operations asynchronous:

User submits order →
 Validate payment (300ms) →
 Check inventory (200ms) →
 Publish "order_placed" event →
 Return response (total: 500ms)

Meanwhile, independent services handle:
 Email service → sends confirmation
 Analytics service → records sale
 Fulfillment service → prepares shipment

Users get immediate feedback. Background services process at their own pace. One slow service doesn't block others.

How most teams mess this up

Creating event spam

// Wrong: too granular
emit('user_email_updated', { userId, newEmail })
emit('user_phone_updated', { userId, newPhone })
emit('user_name_updated', { userId, newName })

// Right: business-focused
emit('user_profile_updated', { userId, changes })

Bloated event payloads

// Wrong: kitchen sink approach
emit('order_placed', {
 order: fullOrderObject,
 user: fullUserObject,
 products: allProductDetails,
 analytics: trackingData
})

// Right: minimal context
emit('order_placed', {
 orderId: '12345',
 userId: '67890',
 timestamp: Date.now()
})

Synchronous event processing

// Wrong: defeats the purpose
const result = await publishAndWait('order_placed', orderData)
return result

// Right: fire and forget
publish('order_placed', orderData)
return { success: true, orderId }

The hybrid approach that actually works

Don't go full event-driven immediately. Start with a hybrid pattern:

Critical path stays synchronous:

  • Payment validation
  • Inventory checks
  • Core business logic

Non-critical operations become asynchronous:

  • Email notifications
  • Analytics updates
  • Audit logging
  • Third-party integrations

This gives you immediate performance gains without the complexity of full event-driven architecture.

When to use each approach

Stick with request-driven for:

  • Simple CRUD applications
  • Small teams (2-5 developers)
  • Workflows requiring immediate consistency
  • Systems with predictable, moderate load

Move to event-driven for:

  • High-volume applications
  • Complex workflows with many independent steps
  • Multi-service architectures
  • Systems requiring audit trails
  • When different components scale at different rates

Real performance impact

A recent client saw these improvements after implementing hybrid architecture:

  • Response times: 800ms → 150ms
  • Concurrent users: 200 → 2000+
  • System availability: 94% → 99.2%
  • Development velocity: significantly faster (independent service deployments)

Key implementation tips

  1. Start small: Convert one non-critical workflow to events first
  2. Handle duplicates: Events can be delivered multiple times
  3. Include event ordering: Use timestamps and sequence numbers
  4. Monitor event lag: Track processing delays
  5. Design for failure: Events can be lost or delayed

The bottom line

Request-driven architecture isn't wrong, it's limited. When synchronous chains become your bottleneck, events offer a path to better performance and scalability.

But don't rearchitect everything overnight. Start with hybrid patterns. Move non-critical operations to events. Keep core workflows synchronous until you understand event-driven complexities.

Your users will thank you for the faster response times, and your team will appreciate the improved system resilience.

Originally published on binadit.com