Brama (Brama v1.0.1)

View Source

Brama is a library for managing connections to external dependencies.

It provides features for:

  • Connection monitoring
  • Circuit breaking
  • Self-healing
  • Status notifications

Connection Management

Brama allows you to register connections to external services and track their status:

# Register a connection
Brama.register("payment_api")

# Check if a connection is available
Brama.available?("payment_api")

# Report success/failure
Brama.success("payment_api")
Brama.failure("payment_api", reason: "Timeout")

Circuit Breaking

Brama implements the circuit breaker pattern to prevent cascading failures:

# Circuit opens automatically after consecutive failures
Brama.failure("payment_api", reason: "Timeout") # After max_attempts, circuit opens

# Manual circuit control
Brama.open_circuit!("payment_api", reason: "Maintenance")
Brama.close_circuit!("payment_api")
Brama.reset_circuit!("payment_api")

Configuration

Brama supports both global and per-connection configuration:

# Update global settings
Brama.configure(max_attempts: 15, expiry: 120_000)

# Update specific connection
Brama.configure("payment_api", max_attempts: 5, expiry: 30_000)

# Register with progressive backoff
Brama.register("flaky_service",
  expiry_strategy: :progressive,
  initial_expiry: 10_000,
  max_expiry: 300_000,
  backoff_factor: 2.0
)

Event Subscription

Subscribe to events to get notified of state changes:

# Subscribe to all events for a specific connection
Brama.subscribe(connection: "payment_api")

# Subscribe to specific event types
Brama.subscribe(events: [:state_change, :failure])

# Subscribe with a filter function
Brama.subscribe(filter: fn event -> event.connection == "payment_api" end)

Summary

Functions

Checks if a connection is available (circuit is closed or half-open).

Manually closes the circuit for a connection.

Updates the configuration for a specific connection or globally.

Reports a failed connection attempt.

Manually opens the circuit for a connection.

Registers a new connection with Brama.

Resets the circuit for a connection (closes it and resets failure count).

Gets the current status of a connection.

Subscribes to connection events.

Reports a successful connection attempt.

Unregisters a connection from Brama.

Unsubscribes from connection events.

Functions

available?(identifier, opts \\ [])

Checks if a connection is available (circuit is closed or half-open).

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match

Examples

iex> Brama.register("payment_api")
iex> Brama.available?("payment_api")
true

close_circuit!(identifier, opts \\ [])

Manually closes the circuit for a connection.

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match

Examples

iex> Brama.register("payment_api")
iex> Brama.close_circuit!("payment_api")
:ok

configure(identifier \\ nil, opts)

@spec configure(
  String.t() | nil,
  keyword()
) :: :ok | {:error, term()}

Updates the configuration for a specific connection or globally.

Parameters

  • identifier - Optional connection identifier. If not provided, updates global settings
  • opts - Configuration options to update:
    • :max_attempts - Maximum number of failures before opening circuit
    • :expiry - Time in milliseconds before open circuit transitions to half-open
    • :expiry_strategy - Either :fixed or :progressive for backoff
    • :initial_expiry - Initial expiry time for progressive backoff
    • :max_expiry - Maximum expiry time for progressive backoff
    • :backoff_factor - Factor for exponential backoff

Examples

# Update global settings
Brama.configure(max_attempts: 15, expiry: 120_000)

# Update specific connection
Brama.configure("payment_api", max_attempts: 5, expiry: 30_000)

# Configure progressive backoff
Brama.configure("flaky_service",
  expiry_strategy: :progressive,
  initial_expiry: 10_000,
  max_expiry: 300_000,
  backoff_factor: 2.0
)

failure(identifier, opts \\ [])

Reports a failed connection attempt.

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match
    • :reason: Reason for the failure
    • :metadata: Additional metadata about the failure

Examples

iex> Brama.register("payment_api")
iex> Brama.failure("payment_api", reason: "Timeout")
:ok

open_circuit!(identifier, opts \\ [])

Manually opens the circuit for a connection.

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match
    • :reason: Reason for opening the circuit
    • :expiry: Custom expiry time in milliseconds

Examples

iex> Brama.register("payment_api")
iex> Brama.open_circuit!("payment_api", reason: "Maintenance")
:ok

register(identifier, opts \\ [])

Registers a new connection with Brama.

Parameters

  • identifier: A unique identifier for the connection
  • opts: Options for the connection
    • :scope: Optional scope for grouping connections
    • :max_attempts: Maximum number of failures before opening the circuit (default: 5)
    • :expiry: Time in milliseconds after which an open circuit transitions to half-open (default: 60000)
    • :metadata: Additional metadata to store with the connection

Examples

iex> {:ok, result} = Brama.register("payment_api")
iex> Map.take(result, [:identifier, :state, :failure_count])
%{identifier: "payment_api", state: :closed, failure_count: 0}

iex> {:ok, result} = Brama.register("invoice_api", scope: "billing", max_attempts: 5)
iex> Map.take(result, [:identifier, :scope, :state, :failure_count])
%{identifier: "invoice_api", scope: "billing", state: :closed, failure_count: 0}

reset_circuit!(identifier, opts \\ [])

Resets the circuit for a connection (closes it and resets failure count).

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match

Examples

iex> Brama.register("payment_api")
iex> Brama.reset_circuit!("payment_api")
:ok

status(identifier, opts \\ [])

Gets the current status of a connection.

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match

Examples

iex> Brama.register("payment_api")
iex> {:ok, result} = Brama.status("payment_api")
iex> Map.take(result, [:state, :failure_count])
%{state: :closed, failure_count: 0}

subscribe(opts)

Subscribes to connection events.

Parameters

  • opts: Subscription options (at least one must be provided)
    • :connection: Filter events by connection identifier
    • :scope: Filter events by connection scope
    • :events: List of event types to subscribe to
    • :filter: Custom filter function

Examples

iex> Brama.subscribe(events: [:state_change])
{:ok, pid}

success(identifier, opts \\ [])

Reports a successful connection attempt.

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match
    • :metadata: Additional metadata about the success

Examples

iex> Brama.register("payment_api")
iex> Brama.success("payment_api")
:ok

unregister(identifier, opts \\ [])

Unregisters a connection from Brama.

Parameters

  • identifier: The connection identifier
  • opts: Options
    • :scope: Optional scope to match

Examples

iex> Brama.register("payment_api")
iex> Brama.unregister("payment_api")
:ok

unsubscribe(subscription_id)

Unsubscribes from connection events.

Parameters

  • subscription_id: The subscription ID returned from subscribe/1

Examples

iex> {:ok, subscription} = Brama.subscribe(events: [:state_change])
iex> Brama.unsubscribe(subscription)
:ok