Definition:
Bulkhead Pattern is a fault tolerance design pattern that isolates critical resources and functionality into separate pools to prevent failures in one area from cascading and bringing down the entire system. Named after ship bulkheads that prevent water from spreading between compartments, this pattern compartmentalizes system components so that if one fails, others continue operating normally.
Key Properties:
- Resource isolation: Separate pools for different operations
- Failure containment: Problems don’t spread across boundaries
- Independent scaling: Each compartment can scale separately
- Performance protection: Critical operations stay unaffected
- Resource allocation: Guaranteed resources for important functions
Core Concept: Instead of sharing resources, create separate “compartments” for different types of operations or users.
Example:
E-commerce Platform
class EcommercePlatform {
constructor() {
this.setupBulkheads();
}
setupBulkheads() {
// Customer-facing bulkhead (highest priority)
this.customerBulkhead = {
database: new ConnectionPool({ max: 15, min: 10 }),
cache: new RedisPool({ max: 10, min: 5 }),
threadPool: new ThreadPool({ core: 8, max: 15 }),
rateLimiter: new RateLimiter({ rpm: 10000 })
};
// Admin operations bulkhead (medium priority)
this.adminBulkhead = {
database: new ConnectionPool({ max: 8, min: 3 }),
cache: new RedisPool({ max: 5, min: 2 }),
threadPool: new ThreadPool({ core: 3, max: 8 }),
rateLimiter: new RateLimiter({ rpm: 1000 })
};
// Analytics bulkhead (lowest priority)
this.analyticsBulkhead = {
database: new ReadReplicaPool({ max: 5, min: 2 }),
cache: new RedisPool({ max: 3, min: 1 }),
threadPool: new ThreadPool({ core: 2, max: 5 }),
rateLimiter: new RateLimiter({ rpm: 100 })
};
// Background jobs bulkhead
this.backgroundBulkhead = {
database: new ConnectionPool({ max: 3, min: 1 }),
threadPool: new ThreadPool({ core: 2, max: 4 }),
rateLimiter: new RateLimiter({ rpm: 50 })
};
}
// Customer operations - highest priority resources
async placeOrder(customerId, orderData) {
return await this.executeInBulkhead('customer', async () => {
console.log('🛒 Processing customer order');
const connection = await this.customerBulkhead.database.getConnection();
const cache = await this.customerBulkhead.cache.getClient();
try {
// Check inventory
const inventory = await cache.get(`inventory:${orderData.productId}`);
if (!inventory || inventory < orderData.quantity) {
const dbInventory = await connection.query(
'SELECT quantity FROM inventory WHERE product_id = ?',
[orderData.productId]
);
if (dbInventory.quantity < orderData.quantity) {
throw new Error('Insufficient inventory');
}
}
// Create order
const order = await connection.query(
'INSERT INTO orders (customer_id, product_id, quantity) VALUES (?, ?, ?)',
[customerId, orderData.productId, orderData.quantity]
);
// Update cache
await cache.decr(`inventory:${orderData.productId}`, orderData.quantity);
return { orderId: order.insertId, status: 'confirmed' };
} finally {
connection.release();
}
});
}
// Admin operations - medium priority resources
async updateProductInfo(productId, updates) {
return await this.executeInBulkhead('admin', async () => {
console.log('⚙️ Admin updating product');
const connection = await this.adminBulkhead.database.getConnection();
try {
return await connection.query(
'UPDATE products SET name = ?, price = ? WHERE id = ?',
[updates.name, updates.price, productId]
);
} finally {
connection.release();
}
});
}
// Analytics - lowest priority resources
async generateSalesReport(startDate, endDate) {
return await this.executeInBulkhead('analytics', async () => {
console.log('📈 Generating analytics report');
const connection = await this.analyticsBulkhead.database.getConnection();
try {
// Heavy analytical query
return await connection.query(`
SELECT
DATE(created_at) as date,
COUNT(*) as orders,
SUM(total) as revenue,
AVG(total) as avg_order_value
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE o.created_at BETWEEN ? AND ?
GROUP BY DATE(created_at)
ORDER BY date
`, [startDate, endDate]);
} finally {
connection.release();
}
});
}
// Background tasks - separate resources
async processEmailQueue() {
return await this.executeInBulkhead('background', async () => {
console.log('📧 Processing background emails');
const connection = await this.backgroundBulkhead.database.getConnection();
try {
const pendingEmails = await connection.query(
'SELECT * FROM email_queue WHERE status = "pending" LIMIT 100'
);
for (const email of pendingEmails) {
await this.sendEmail(email);
await connection.query(
'UPDATE email_queue SET status = "sent" WHERE id = ?',
[email.id]
);
}
return { processed: pendingEmails.length };
} finally {
connection.release();
}
});
}
async executeInBulkhead(bulkheadType, operation) {
const bulkhead = this.getBulkhead(bulkheadType);
// Check rate limiting
if (!await bulkhead.rateLimiter.allowRequest()) {
throw new Error(`Rate limit exceeded for ${bulkheadType} operations`);
}
// Execute in thread pool
return await bulkhead.threadPool.execute(operation);
}
getBulkhead(type) {
const bulkheads = {
'customer': this.customerBulkhead,
'admin': this.adminBulkhead,
'analytics': this.analyticsBulkhead,
'background': this.backgroundBulkhead
};
return bulkheads[type];
}
// Monitoring and health checks
async getBulkheadStatus() {
return {
customer: {
activeConnections: this.customerBulkhead.database.activeConnections,
queueLength: this.customerBulkhead.threadPool.queueLength,
rateLimitRemaining: this.customerBulkhead.rateLimiter.remaining
},
admin: {
activeConnections: this.adminBulkhead.database.activeConnections,
queueLength: this.adminBulkhead.threadPool.queueLength
},
analytics: {
activeConnections: this.analyticsBulkhead.database.activeConnections,
queueLength: this.analyticsBulkhead.threadPool.queueLength
},
background: {
activeConnections: this.backgroundBulkhead.database.activeConnections,
queueLength: this.backgroundBulkhead.threadPool.queueLength
}
};
}
}
// Usage example
const platform = new EcommercePlatform();
// Simulate different types of load
async function simulateLoad() {
const results = await Promise.allSettled([
// Customer operations (critical) - will always work
platform.placeOrder('customer123', { productId: 1, quantity: 2 }),
platform.placeOrder('customer456', { productId: 2, quantity: 1 }),
// Admin operations (medium priority) - works if resources available
platform.updateProductInfo(1, { name: 'New Product Name', price: 29.99 }),
// Analytics (low priority) - might be throttled
platform.generateSalesReport('2023-01-01', '2023-12-31'),
// Background tasks (lowest priority) - runs when possible
platform.processEmailQueue()
]);
console.log('Results:', results.map(r => r.status));
// Check bulkhead health
const status = await platform.getBulkheadStatus();
console.log('Bulkhead Status:', status);
}
simulateLoad();