Skip to content

Fallback

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

Fallback Pattern Guide

The Fallback pattern provides alternative results when operations fail, enabling graceful degradation.

When to Use

  • You have cached data as an alternative
  • You can return default values
  • You can provide degraded functionality
  • You want to ensure operations always return a result

When NOT to Use

  • Failures should propagate (no reasonable fallback)
  • Operations must succeed or fail (no middle ground)
  • Fallback is as expensive as the primary operation

Quick Start

uses Murphy.Policy.Fallback;

var
  Policy: IFallbackPolicy<string>;
  Data: string;
begin
  Policy := TFallbackBuilder<string>
    .Handle(Exception)
    .Fallback(function: string begin Result := 'Default Value'; end)
    .Build;

  Data := Policy.Execute(function: string begin Result := FetchData; end);
end;

Common Scenarios

Cached Data Fallback

type
  TDataService = class
  private
    FCache: string;
  public
    function GetData: string;
  end;

function TDataService.GetData: string;
var
  Policy: IFallbackPolicy<string>;
begin
  Policy := TFallbackBuilder<string>
    .Handle(Exception)
    .Fallback(function: string
              begin
                WriteLn('Using cached data');
                Result := FCache;
              end)
    .Build;

  Result := Policy.Execute(
    function: string
    begin
      var Fresh := FetchFromAPI;
      FCache := Fresh;  // Update cache
      Result := Fresh;
    end);
end;

Default Values

function GetUserPreference(Key: string): string;
var
  Policy: IFallbackPolicy<string>;
begin
  Policy := TFallbackBuilder<string>
    .Handle(Exception)
    .Fallback(function: string begin Result := 'default'; end)
    .Build;

  Result := Policy.Execute(
    function: string
    begin
      Result := Database.Query('SELECT value FROM prefs WHERE key = ?', [Key]);
    end);
end;

Fallback Chain

function GetConfig: string;
var
  DatabasePolicy, FilePolicy: IFallbackPolicy<string>;
begin
  // Try database, fall back to file
  DatabasePolicy := TFallbackBuilder<string>
    .Handle(EDatabaseError)
    .Fallback(function: string begin Result := ReadConfigFile; end)
    .Build;

  // Try API, fall back to database/file
  FilePolicy := TFallbackBuilder<string>
    .Handle(Exception)
    .Fallback(function: string
              begin
                Result := DatabasePolicy.Execute(
                  function: string begin Result := GetFromDatabase; end);
              end)
    .Build;

  Result := FilePolicy.Execute(function: string begin Result := GetFromAPI; end);
end;

Best Practices

  1. Fallback should be reliable - Don't let fallback throw exceptions
  2. Indicate degraded mode - Log when fallback is used
  3. Consider staleness - Cached data may be outdated
  4. Memory management - Be careful with object-based fallbacks
  5. Test fallback paths - Ensure they work correctly

See Also


Back to Index

Clone this wiki locally