Documentation Index
Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The bulkhead middleware implements the bulkhead pattern, limiting concurrent requests to prevent cascade failures and ensure fair resource allocation.
Use it when you need:
- Failure isolation between services
- Concurrent request limiting
- Resource protection
Installation
import "github.com/go-mizu/mizu/middlewares/bulkhead"
Quick Start
app := mizu.New()
// Limit to 10 concurrent requests
app.Use(bulkhead.New(10))
Configuration
Options
| Option | Type | Default | Description |
|---|
MaxConcurrent | int | Required | Max concurrent requests |
MaxWaiting | int | 0 | Max waiting requests (0 = reject) |
Timeout | time.Duration | 0 | Wait timeout |
ErrorHandler | func(*mizu.Ctx) error | - | Custom rejection handler |
Examples
Simple Limit
// Reject if more than 10 concurrent
app.Use(bulkhead.New(10))
With Waiting Queue
// Allow 10 concurrent, 20 waiting
app.Use(bulkhead.WithOptions(bulkhead.Options{
MaxConcurrent: 10,
MaxWaiting: 20,
}))
With Timeout
// Wait up to 5 seconds for slot
app.Use(bulkhead.WithOptions(bulkhead.Options{
MaxConcurrent: 10,
MaxWaiting: 50,
Timeout: 5 * time.Second,
}))
Per-Route Limits
// Different limits for different routes
api := app.Group("/api")
api.Use(bulkhead.New(100))
heavy := app.Group("/heavy")
heavy.Use(bulkhead.New(5))
Custom Error
app.Use(bulkhead.WithOptions(bulkhead.Options{
MaxConcurrent: 10,
ErrorHandler: func(c *mizu.Ctx) error {
return c.JSON(503, map[string]string{
"error": "Service temporarily unavailable",
})
},
}))
API Reference
Functions
// New creates bulkhead with max concurrent
func New(maxConcurrent int) mizu.Middleware
// WithOptions creates bulkhead with configuration
func WithOptions(opts Options) mizu.Middleware
How It Works
- Request arrives
- Check if under concurrent limit
- If under: acquire slot, process, release
- If over: check waiting queue
- If queue full or timeout: reject with 503
HTTP Status Codes
| Code | Meaning |
|---|
| 503 | Service unavailable (bulkhead full) |
Technical Details
Implementation
The bulkhead middleware uses a semaphore pattern with buffered channels to control concurrency:
- Semaphore Channel: A buffered channel with capacity equal to
MaxConcurrent acts as the semaphore for slot allocation
- Waiting Queue: A counter tracks the number of requests waiting for a slot, capped at
MaxWait
- Non-blocking Acquire: First attempts to acquire a slot without blocking using
select with default
- Blocking Wait: If no slot is available, increments the waiting counter and blocks until a slot becomes available or context is cancelled
- Thread Safety: Uses
sync.Mutex to protect the waiting counter and ensure thread-safe operations
Core Components
Bulkhead Structure:
sem chan struct{}: Buffered channel for semaphore-based slot management
waiting int: Current number of requests in the waiting queue
maxWait int: Maximum allowed requests in the waiting queue
mu sync.Mutex: Mutex for protecting shared state
Manager:
- Manages multiple named bulkheads for isolation between different services or paths
- Thread-safe bulkhead creation and retrieval using
sync.RWMutex
- Provides aggregated statistics across all managed bulkheads
Statistics:
- Real-time metrics including active requests, waiting requests, and available slots
- Useful for monitoring and debugging bulkhead behavior
Request Flow
- Request arrives at middleware
- Attempts non-blocking slot acquisition via
select statement
- If slot acquired: processes request and releases slot via
defer
- If no slot available:
- Checks if waiting queue is full
- If full: rejects immediately with error handler or 503 status
- If space available: increments waiting counter and blocks on semaphore channel
- When slot becomes available or context cancelled: decrements waiting counter
- On context cancellation: returns context error (e.g., timeout, cancellation)
Best Practices
- Set limits based on resource capacity
- Use different bulkheads for different services
- Monitor rejection rates
- Combine with circuit breaker for full resilience
Testing
Test Coverage
| Test Case | Description | Expected Behavior |
|---|
TestNew | Tests basic bulkhead functionality with concurrent requests | Some requests succeed (200), others are rejected (503) when bulkhead is full |
TestBulkhead_Stats | Validates bulkhead statistics reporting | Returns correct name, max active count, and available slots |
TestNewBulkhead_ErrorHandler | Tests custom error handler for rejected requests | Rejected requests use custom error handler with 429 status instead of default 503 |
TestManager | Tests bulkhead manager’s get-or-create behavior | Returns same bulkhead instance for same name, different instances for different names |
TestManager_Stats | Validates manager’s aggregated statistics | Returns stats for all managed bulkheads by name |
TestForPath | Tests path-based bulkhead isolation | Creates separate bulkheads for different URL paths |
TestDefaults | Validates default configuration values | Uses default values of 10 for MaxConcurrent and MaxWait when not specified |