# Bulkhead Pattern Guide The Bulkhead pattern limits the number of concurrent executions of an operation, isolating resources so that one overloaded workload cannot exhaust the whole system. ## When to Use - Protecting a limited resource (a connection pool, a worker pool, a downstream service) from being overwhelmed - Isolating one workload from another, so a spike in one area does not starve the rest of the application - Capping parallel work submitted to a slow or expensive dependency ## When NOT to Use - Operations that are cheap and cannot meaningfully contend for a shared resource - When you need calls to queue and wait for a free slot rather than fail immediately - Bulkhead rejects on saturation, it does not queue - As a substitute for a real connection/thread pool with its own admission control ## Quick Start ```pascal uses Murphy.Policy.Bulkhead; var Policy: IBulkheadPolicy; begin Policy := TBulkheadBuilder .Handle([]) .Limit(10) .Build; Policy.Execute(procedure begin ProcessRequest; end); end; ``` ## Common Scenarios ### Protecting a Connection Pool ```pascal procedure QueryDatabase; var Policy: IBulkheadPolicy; begin Policy := TBulkheadBuilder .Handle([]) .Limit(5) // No more than 5 concurrent queries .Build; Policy.Execute( procedure begin Database.Execute('SELECT * FROM orders'); end); end; ``` ### Handling Rejection ```pascal var Policy: IBulkheadPolicy; begin Policy := TBulkheadBuilder.Handle([]).Limit(20).Build; try Policy.Execute(procedure begin ProcessRequest; end); except on E: EBulkheadRejectedException do WriteLn('Rejected: too many concurrent requests'); end; end; ``` ### Monitoring Current Load ```pascal var Policy: IBulkheadPolicy; begin Policy := TBulkheadBuilder.Handle([]).Limit(10).Build; WriteLn(Format('Currently executing: %d/10', [Policy.ExecutionCount])); end; ``` ### Combined with Retry Retry a rejected call after a short wait, giving the bulkhead a chance to free a slot: ```pascal uses Murphy.Policy.Retry, Murphy.Policy.Bulkhead, Murphy.Policy.Wrap; var Policy: IPolicyWrap; begin Policy := TPolicyWrapBuilder.Wrap([ TRetryBuilder.Handle(EBulkheadRejectedException).Retry(3).Wait(TTimeSpan.FromMilliseconds(200)), TBulkheadBuilder.Handle([]).Limit(10) ]); Policy.Execute(procedure begin ProcessRequest; end); end; ``` ## Best Practices 1. **Size the limit to the resource, not to guesswork** - base it on pool size, thread budget, or measured capacity 2. **Rejection is immediate** - the bulkhead never queues; pair with Retry if callers should wait and try again 3. **Use one bulkhead instance per resource** - create a separate policy for each pool or workload you want to isolate 4. **`Handle()` is not used for filtering** - every call counts against the limit regardless of exception type 5. **Monitor `ExecutionCount`** - useful to tune the limit or expose it in health checks ## See Also - [Bulkhead API Reference](../API-Reference/Bulkhead-Policy.md) - [Combining Patterns](Combining-Patterns.md) --- [Back to Index](../Home.md)