-
Notifications
You must be signed in to change notification settings - Fork 1
Bulkhead
Marco Breveglieri edited this page Jul 20, 2026
·
1 revision
The Bulkhead pattern limits the number of concurrent executions of an operation, isolating resources so that one overloaded workload cannot exhaust the whole system.
- 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
- 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
uses Murphy.Policy.Bulkhead;
var
Policy: IBulkheadPolicy;
begin
Policy := TBulkheadBuilder
.Handle([])
.Limit(10)
.Build;
Policy.Execute(procedure begin ProcessRequest; end);
end;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;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;var Policy: IBulkheadPolicy;
begin
Policy := TBulkheadBuilder.Handle([]).Limit(10).Build;
WriteLn(Format('Currently executing: %d/10', [Policy.ExecutionCount]));
end;Retry a rejected call after a short wait, giving the bulkhead a chance to free a slot:
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;- Size the limit to the resource, not to guesswork - base it on pool size, thread budget, or measured capacity
- Rejection is immediate - the bulkhead never queues; pair with Retry if callers should wait and try again
- Use one bulkhead instance per resource - create a separate policy for each pool or workload you want to isolate
-
Handle()is not used for filtering - every call counts against the limit regardless of exception type -
Monitor
ExecutionCount- useful to tune the limit or expose it in health checks