Use Cases for Event-Driven Architecture
Event-driven architecture is ideal when you have loosely coupled systems that need to react to changes or when actions trigger multiple side effects. Here are some practical use cases:
1. E-Commerce Order Processing
When a user places an order, multiple things need to happen independently:
const EventEmitter = require('events');
class OrderSystem extends EventEmitter {
placeOrder(order) {
console.log(`Order placed: ${order.id}`);
// Emit event instead of calling functions directly
this.emit('orderPlaced', order);
return { success: true, orderId: order.id };
}
}
const orderSystem = new OrderSystem();
// Different services listen for the event
orderSystem.on('orderPlaced', (order) => {
console.log('📧 Sending confirmation email to:', order.customerEmail);
});
orderSystem.on('orderPlaced', (order) => {
console.log('📦 Updating inventory for items:', order.items);
});
orderSystem.on('orderPlaced', (order) => {
console.log('💳 Processing payment of $', order.total);
});
orderSystem.on('orderPlaced', (order) => {
console.log('📊 Logging analytics event');
});
orderSystem.on('orderPlaced', (order) => {
console.log('🔔 Notifying warehouse for shipment');
});
// Place an order - all listeners react automatically
orderSystem.placeOrder({
id: '12345',
customerEmail: 'user@example.com',
items: ['laptop', 'mouse'],
total: 1299.99
});
Why event-driven here?
- Each service (email, inventory, payment) operates independently
- Easy to add new services without modifying order placement code
- Services can fail independently without breaking the order flow
2. Real-Time Notifications System
const EventEmitter = require('events');
class NotificationService extends EventEmitter {
constructor() {
super();
this.setupListeners();
}
setupListeners() {
// Listen for various app events
this.on('userSignup', (user) => {
this.sendWelcomeEmail(user);
this.sendSlackNotification(`New user: ${user.name}`);
});
this.on('commentAdded', (data) => {
this.notifyPostAuthor(data);
this.pushNotification(data.userId, 'New comment on your post');
});
this.on('paymentFailed', (data) => {
this.sendUrgentEmail(data.userId);
this.sendSMS(data.phone, 'Payment failed');
});
}
sendWelcomeEmail(user) {
console.log(`✉️ Sending welcome email to ${user.email}`);
}
sendSlackNotification(message) {
console.log(`💬 Slack: ${message}`);
}
notifyPostAuthor(data) {
console.log(`🔔 Notifying post author about comment`);
}
pushNotification(userId, message) {
console.log(`📱 Push to ${userId}: ${message}`);
}
sendUrgentEmail(userId) {
console.log(`🚨 Urgent email to user ${userId}`);
}
sendSMS(phone, message) {
console.log(`📲 SMS to ${phone}: ${message}`);
}
}
// Usage
const notifications = new NotificationService();
// Anywhere in your app, emit events
notifications.emit('userSignup', {
name: 'Alice',
email: 'alice@example.com'
});
notifications.emit('commentAdded', {
userId: '123',
postId: '456',
comment: 'Great post!'
});
3. File Upload Processing Pipeline
const EventEmitter = require('events');
const fs = require('fs');
class FileProcessor extends EventEmitter {
uploadFile(file) {
console.log(`📁 File uploaded: ${file.name}`);
this.emit('fileUploaded', file);
}
}
const processor = new FileProcessor();
// Image processing pipeline
processor.on('fileUploaded', async (file) => {
if (file.type === 'image') {
console.log('🖼️ Generating thumbnail...');
// Simulate async processing
setTimeout(() => {
processor.emit('thumbnailCreated', { file, thumbnail: 'thumb.jpg' });
}, 1000);
}
});
processor.on('thumbnailCreated', (data) => {
console.log('☁️ Uploading to cloud storage...');
processor.emit('cloudUploadComplete', data);
});
processor.on('cloudUploadComplete', (data) => {
console.log('🗄️ Updating database with file URL...');
});
processor.on('fileUploaded', (file) => {
console.log('🦠 Running virus scan...');
});
processor.on('fileUploaded', (file) => {
console.log('📊 Updating user storage quota...');
});
// Trigger the pipeline
processor.uploadFile({
name: 'photo.jpg',
type: 'image',
size: 2048576
});
4. Chat Application
const EventEmitter = require('events');
class ChatRoom extends EventEmitter {
constructor(name) {
super();
this.name = name;
this.users = new Map();
}
addUser(userId, username) {
this.users.set(userId, username);
this.emit('userJoined', { userId, username });
}
removeUser(userId) {
const username = this.users.get(userId);
this.users.delete(userId);
this.emit('userLeft', { userId, username });
}
sendMessage(userId, message) {
this.emit('message', {
userId,
username: this.users.get(userId),
message,
timestamp: new Date()
});
}
}
const gameRoom = new ChatRoom('Gaming');
// Different clients listen for events
gameRoom.on('userJoined', (data) => {
console.log(`👋 ${data.username} joined the chat`);
});
gameRoom.on('userLeft', (data) => {
console.log(`👋 ${data.username} left the chat`);
});
gameRoom.on('message', (data) => {
console.log(`[${data.timestamp.toLocaleTimeString()}] ${data.username}: ${data.message}`);
// Trigger secondary events
if (data.message.includes('@everyone')) {
gameRoom.emit('mentionEveryone', data);
}
});
gameRoom.on('mentionEveryone', (data) => {
console.log('🔔 Sending notifications to all users...');
});
// Simulate chat activity
gameRoom.addUser('user1', 'Alice');
gameRoom.addUser('user2', 'Bob');
gameRoom.sendMessage('user1', 'Hey everyone!');
gameRoom.sendMessage('user2', '@everyone check this out!');
gameRoom.removeUser('user1');
5. Microservices Communication
const EventEmitter = require('events');
// Central event bus
class EventBus extends EventEmitter {}
const eventBus = new EventBus();
// User Service
class UserService {
constructor(eventBus) {
this.eventBus = eventBus;
}
createUser(userData) {
const user = { id: Date.now(), ...userData };
console.log('👤 User created:', user.email);
// Publish event
this.eventBus.emit('user.created', user);
return user;
}
}
// Email Service (subscribes to user events)
class EmailService {
constructor(eventBus) {
eventBus.on('user.created', (user) => {
this.sendWelcomeEmail(user);
});
eventBus.on('order.completed', (order) => {
this.sendOrderConfirmation(order);
});
}
sendWelcomeEmail(user) {
console.log('📧 Sending welcome email to:', user.email);
}
sendOrderConfirmation(order) {
console.log('📧 Sending order confirmation');
}
}
// Analytics Service
class AnalyticsService {
constructor(eventBus) {
eventBus.on('user.created', (user) => {
console.log('📊 Tracking new user signup');
});
eventBus.on('order.completed', (order) => {
console.log('📊 Tracking order completion');
});
}
}
// Setup services
const userService = new UserService(eventBus);
const emailService = new EmailService(eventBus);
const analyticsService = new AnalyticsService(eventBus);
// Create a user - other services react automatically
userService.createUser({
email: 'newuser@example.com',
name: 'Charlie'
});
Key Benefits of Event-Driven Architecture:
- Loose Coupling: Services don't need to know about each other
- Scalability: Easy to add new event listeners without changing existing code
- Asynchronous: Non-blocking operations that can happen in parallel
- Flexibility: Easy to add/remove functionality
- Real-time: Perfect for applications that need instant reactions
Event-driven architecture shines when you have systems where one action needs to trigger multiple independent reactions, especially when those reactions might be added or modified over time.