Skip to content

Bulkhead Policy

Marco Breveglieri edited this page Jul 20, 2026 · 1 revision

Bulkhead Policy API

Unit: Murphy.Policy.Bulkhead

The Bulkhead policy limits the number of concurrent executions of an operation, isolating resources so that one workload cannot exhaust the whole system.

Overview

The Bulkhead pattern is useful for capping concurrency, such as:

  • Protecting a connection pool from being overwhelmed
  • Isolating one workload from another
  • Preventing a burst of calls from starving shared resources

Table of Contents


IBulkheadPolicy Interface

The interface for the Bulkhead policy pattern. Extends IExecutablePolicy, so a Bulkhead policy can participate in a Policy Wrap.

Declaration

type
  IBulkheadPolicy = interface(IExecutablePolicy)
    ['{22323982-6EE4-47B9-851F-A11E8B4ABFB2}']
    function ExecutionCount: Integer;
    function Limit(AMaxParallelization: Integer): IBulkheadPolicy;
  end;

Methods

Execute

procedure Execute(AProc: TProc);

Description: Executes AProc if a slot is available, otherwise rejects the call immediately.

Behavior:

  1. Acquires an execution slot under a lock; if the limit is already reached, raises EBulkheadRejectedException without running AProc
  2. Runs AProc outside the lock, so accepted calls execute in parallel
  3. Always releases the slot afterwards, even if AProc raises

Note: Exception filtering configured via Handle() is not applied by this policy - calls are limited regardless of exception type, and any exception raised by AProc is re-raised untouched. Rejected calls are not queued.

ExecutionCount

function ExecutionCount: Integer;

Description: Returns the number of executions currently in progress.

Returns: Integer - Current concurrent execution count (thread-safe read)

Use Cases: Monitoring current load, exposing health-check metrics

Limit

function Limit(AMaxParallelization: Integer): IBulkheadPolicy;

Description: Configures the maximum number of concurrent executions allowed.

Parameters:

  • AMaxParallelization: Integer - Maximum concurrent executions

Returns: IBulkheadPolicy - Self for method chaining

Default: 10 if not specified

Example:

Policy := TBulkheadBuilder
  .Handle([])
  .Limit(5)
  .Build;

TBulkheadPolicy Class

Concrete implementation of the Bulkhead policy pattern.

Declaration

type
  TBulkheadPolicy = class(TPolicy, IBulkheadPolicy)
  private
    FExecutionCount: Integer;
    FMaxParallelization: Integer;
  public
    constructor Create(AExceptionTypes: TArray<ExceptClass>); override;
    procedure Execute(AProc: TProc);
    function ExecutionCount: Integer;
    function Limit(AMaxParallelization: Integer): IBulkheadPolicy;
  end;

Constructor

constructor Create(AExceptionTypes: TArray<ExceptClass>); override;

Defaults:

  • FMaxParallelization: 10
  • FExecutionCount: 0

Note: Typically called by TBulkheadBuilder, not directly by users.

Implementation Details

Slot acquisition, release, and the ExecutionCount read are all synchronized via TMonitor on the policy instance. The action itself always runs outside the lock, so accepted calls execute concurrently up to the configured limit.


TBulkheadBuilder Class

Builder class for creating Bulkhead policies with fluent configuration.

Declaration

type
  TBulkheadBuilder = class sealed(TPolicyBuilder<IBulkheadPolicy>)
  public
    class function Handle(AExceptionTypes: TArray<ExceptClass>): IBulkheadPolicy; override;
  end;

Handle

class function Handle(AExceptionTypes: TArray<ExceptClass>): IBulkheadPolicy; override;

Description: Creates a new Bulkhead policy instance. The exception types passed here are not used by this policy: calls are limited regardless of any exception filter. Pass [] for clarity.

Returns: IBulkheadPolicy - Policy instance ready for further configuration


Usage Examples

Example 1: Basic Bulkhead

uses
  Murphy.Policy.Bulkhead;

var
  Policy: IBulkheadPolicy;
begin
  Policy := TBulkheadBuilder
    .Handle([])
    .Limit(10)
    .Build;

  Policy.Execute(
    procedure
    begin
      ProcessRequest;
    end);
end;

Example 2: Handling Rejection

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;

Example 3: Bulkhead with Retry

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;

See Also


← Timeout Policy | API Reference Index | Cache Policy →

Clone this wiki locally