Skip to content
Marco Breveglieri edited this page Jul 20, 2026 · 2 revisions

Retry Pattern Guide

The Retry pattern automatically retries failed operations, handling transient failures gracefully.

When to Use

  • Network requests that may timeout temporarily
  • Database operations with transient connection issues
  • File operations on network drives
  • API calls to services with intermittent availability

When NOT to Use

  • Operations that are not idempotent (executing multiple times causes issues)
  • Permanent failures (invalid credentials, 404 errors)
  • Operations with side effects that shouldn't be repeated

Quick Start

uses Murphy.Policy.Retry;

var
  Policy: IRetryPolicy;
begin
  Policy := TRetryBuilder
    .Handle(EIdHTTPProtocolException)
    .Retry(3)
    .Wait(TTimeSpan.FromSeconds(1))
    .Build;

  Policy.Execute(procedure begin HTTP.Get('https://api.example.com'); end);
end;

Common Scenarios

HTTP API Calls

function FetchUserData(UserId: Integer): string;
var
  RetryPolicy: IRetryPolicy;
begin
  RetryPolicy := TRetryBuilder
    .Handle([EIdHTTPProtocolException, EIdSocketError])
    .Retry(3)
    .Wait(TTimeSpan.FromSeconds(2))
    .Build;

  Result := RetryPolicy.Execute(
    function: string
    begin
      Result := HTTP.Get(Format('https://api.example.com/users/%d', [UserId]));
    end);
end;

Database Operations

procedure SaveToDatabase(Data: string);
var
  Policy: IRetryPolicy;
begin
  Policy := TRetryBuilder
    .Handle(EDatabaseError)
    .Retry(2)
    .Wait(TTimeSpan.FromMilliseconds(500))
    .Build;

  Policy.Execute(
    procedure
    begin
      Database.Connect;
      Database.Execute('INSERT INTO logs VALUES (' + QuotedStr(Data) + ')');
    end);
end;

Exponential Backoff

var Policy: IRetryPolicy;
begin
  Policy := TRetryBuilder
    .Handle(Exception)
    .Retry(5)
    .Wait(TTimeSpan.FromSeconds(1))
    .When(function(Ctx: TRetryContext): Boolean
          begin
            WriteLn(Format('Retry %d, waiting %dms',
              [Ctx.Attempts, Trunc(Ctx.WaitDelay.TotalMilliseconds)]));
            Ctx.WaitDelay := TTimeSpan.FromMilliseconds(
              Ctx.WaitDelay.TotalMilliseconds * 2);
            Result := True;
          end)
    .Build;
end;
// Delays: 1s, 2s, 4s, 8s, 16s

Conditional Retry

var Policy: IRetryPolicy;
begin
  Policy := TRetryBuilder
    .Handle(EIdHTTPProtocolException)
    .Retry(5)
    .When(function(Ctx: TRetryContext): Boolean
          begin
            var Ex := EIdHTTPProtocolException(Ctx.Exception);
            Result := (Ex.ErrorCode = 503) or (Ex.ErrorCode = 429);
          end)
    .Build;
end;

Best Practices

  1. Use specific exceptions - Don't catch all exceptions
  2. Set reasonable limits - Too many retries waste resources
  3. Add delays - Immediate retries often fail again
  4. Consider exponential backoff - For better server recovery
  5. Log retry attempts - For debugging and monitoring

See Also


Back to Index

Clone this wiki locally