Configuration Guide

View Source

This guide covers all configuration options for erl-esdb, with examples for both Erlang (sys.config) and Elixir (config.exs).

Quick Start

Erlang (sys.config)

[
  {erl_esdb, [
    {stores, [
      {my_store, [
        {data_dir, "/var/lib/erl_esdb/my_store"},
        {mode, single},
        {timeout, 5000},
        {writer_pool_size, 10},
        {reader_pool_size, 10}
      ]}
    ]},
    {telemetry_handlers, [logger]}
  ]}
].

Elixir (config.exs)

config :erl_esdb,
  stores: [
    my_store: [
      data_dir: "/var/lib/erl_esdb/my_store",
      mode: :single,
      timeout: 5_000,
      writer_pool_size: 10,
      reader_pool_size: 10
    ]
  ],
  telemetry_handlers: [:logger]

Configuration Reference

Store Configuration

Stores are the primary configuration. Each store is an independent event store instance backed by Khepri/Ra.

OptionTypeDefaultDescription
storesproplist[]List of store configurations

Each store in the list has:

OptionTypeDefaultDescription
data_dirstring/var/lib/erl_esdb/{store_id}Data directory for Khepri/Ra
modeatomsingleOperation mode: single or cluster
timeoutinteger5000Default timeout in milliseconds
writer_pool_sizeinteger10Number of writer workers
reader_pool_sizeinteger10Number of reader workers
gateway_pool_sizeinteger1Number of gateway workers

Erlang Example

{stores, [
  {orders_store, [
    {data_dir, "/bulk0/erl_esdb/orders"},
    {mode, cluster},
    {timeout, 10000},
    {writer_pool_size, 20},
    {reader_pool_size, 50}
  ]},
  {users_store, [
    {data_dir, "/bulk0/erl_esdb/users"},
    {mode, single},
    {writer_pool_size, 5},
    {reader_pool_size, 10}
  ]}
]}

Elixir Example

config :erl_esdb,
  stores: [
    orders_store: [
      data_dir: "/bulk0/erl_esdb/orders",
      mode: :cluster,
      timeout: 10_000,
      writer_pool_size: 20,
      reader_pool_size: 50
    ],
    users_store: [
      data_dir: "/bulk0/erl_esdb/users",
      mode: :single,
      writer_pool_size: 5,
      reader_pool_size: 10
    ]
  ]

Pool Sizes (Global Defaults)

These set defaults for all stores that don't specify their own values.

OptionTypeDefaultDescription
writer_pool_sizeinteger10Default writer pool size
reader_pool_sizeinteger10Default reader pool size
gateway_pool_sizeinteger1Default gateway pool size

Erlang Example

{writer_pool_size, 20},
{reader_pool_size, 50},
{gateway_pool_size, 2}

Elixir Example

config :erl_esdb,
  writer_pool_size: 20,
  reader_pool_size: 50,
  gateway_pool_size: 2

Worker Timeouts

Idle timeout for reader and writer workers.

OptionTypeDefaultDescription
reader_idle_timeout_msinteger60000Reader idle timeout (ms)
writer_idle_timeout_msinteger60000Writer idle timeout (ms)

Erlang Example

{reader_idle_timeout_ms, 120000},  %% 2 minutes
{writer_idle_timeout_ms, 120000}

Elixir Example

config :erl_esdb,
  reader_idle_timeout_ms: 120_000,
  writer_idle_timeout_ms: 120_000

Health Probing

Health probing monitors store nodes and triggers failover in cluster mode.

OptionTypeDefaultDescription
health_probe_intervalinteger5000Probe interval in milliseconds
health_probe_timeoutinteger2000Probe timeout in milliseconds
health_failure_thresholdinteger3Failures before marking unhealthy
health_probe_typeatompingProbe type: ping or deep

Probe Types:

  • ping - Simple node reachability check (fast, low overhead)
  • deep - Checks Khepri/Ra cluster health (thorough, higher overhead)

Erlang Example

{health_probe_interval, 10000},
{health_probe_timeout, 5000},
{health_failure_threshold, 5},
{health_probe_type, deep}

Elixir Example

config :erl_esdb,
  health_probe_interval: 10_000,
  health_probe_timeout: 5_000,
  health_failure_threshold: 5,
  health_probe_type: :deep

Consistency Checking

Periodic consistency verification for cluster mode.

OptionTypeDefaultDescription
consistency_check_intervalinteger60000Check interval in milliseconds

Erlang Example

{consistency_check_interval, 30000}  %% 30 seconds

Elixir Example

config :erl_esdb,
  consistency_check_interval: 30_000

Persistence

Controls periodic snapshot persistence to disk.

OptionTypeDefaultDescription
persistence_intervalinteger60000Persistence interval in milliseconds

Erlang Example

{persistence_interval, 30000}  %% 30 seconds

Elixir Example

config :erl_esdb,
  persistence_interval: 30_000

Telemetry

Configure telemetry handlers for metrics and logging.

OptionTypeDefaultDescription
telemetry_handlerslist[logger]List of telemetry handlers

Available Handlers:

  • logger - Logs events via OTP logger

Erlang Example

{telemetry_handlers, [logger]}

Elixir Example

config :erl_esdb,
  telemetry_handlers: [:logger]

Complete Configuration Examples

Single Node Development

%% Erlang sys.config
[
  {erl_esdb, [
    {stores, [
      {dev_store, [
        {data_dir, "/tmp/erl_esdb/dev"},
        {mode, single}
      ]}
    ]},
    %% Small pools for development
    {writer_pool_size, 2},
    {reader_pool_size, 5},
    %% Fast feedback on issues
    {health_probe_interval, 2000},
    {health_failure_threshold, 1},
    %% Frequent persistence for testing
    {persistence_interval, 5000}
  ]}
].
# Elixir config/dev.exs
config :erl_esdb,
  stores: [
    dev_store: [
      data_dir: "/tmp/erl_esdb/dev",
      mode: :single
    ]
  ],
  writer_pool_size: 2,
  reader_pool_size: 5,
  health_probe_interval: 2_000,
  health_failure_threshold: 1,
  persistence_interval: 5_000

Production Cluster

%% Erlang sys.config
[
  {erl_esdb, [
    {stores, [
      {main_store, [
        {data_dir, "/bulk0/erl_esdb/main"},
        {mode, cluster},
        {timeout, 10000},
        {writer_pool_size, 50},
        {reader_pool_size, 100},
        {gateway_pool_size, 5}
      ]}
    ]},
    %% Production health monitoring
    {health_probe_interval, 5000},
    {health_probe_timeout, 3000},
    {health_failure_threshold, 3},
    {health_probe_type, deep},
    %% Consistency and persistence
    {consistency_check_interval, 60000},
    {persistence_interval, 30000},
    %% Longer idle timeouts
    {reader_idle_timeout_ms, 300000},
    {writer_idle_timeout_ms, 300000}
  ]}
].
# Elixir config/runtime.exs
config :erl_esdb,
  stores: [
    main_store: [
      data_dir: "/bulk0/erl_esdb/main",
      mode: :cluster,
      timeout: 10_000,
      writer_pool_size: 50,
      reader_pool_size: 100,
      gateway_pool_size: 5
    ]
  ],
  # Production health monitoring
  health_probe_interval: 5_000,
  health_probe_timeout: 3_000,
  health_failure_threshold: 3,
  health_probe_type: :deep,
  # Consistency and persistence
  consistency_check_interval: 60_000,
  persistence_interval: 30_000,
  # Longer idle timeouts
  reader_idle_timeout_ms: 300_000,
  writer_idle_timeout_ms: 300_000

Multi-Store Setup

# Elixir config.exs - Multiple stores for different domains
config :erl_esdb,
  stores: [
    # High-write orders store
    orders_store: [
      data_dir: "/bulk0/erl_esdb/orders",
      mode: :cluster,
      writer_pool_size: 100,
      reader_pool_size: 50
    ],
    # Read-heavy analytics store
    analytics_store: [
      data_dir: "/bulk1/erl_esdb/analytics",
      mode: :single,
      writer_pool_size: 5,
      reader_pool_size: 200
    ],
    # Low-volume user store
    users_store: [
      data_dir: "/bulk0/erl_esdb/users",
      mode: :single,
      writer_pool_size: 10,
      reader_pool_size: 20
    ]
  ]

Cluster Mode Configuration

When running in cluster mode, additional Erlang VM configuration is needed.

vm.args

## Node name (required for clustering)
-name store1@192.168.1.10

## Cookie for cluster authentication
-setcookie my_cluster_cookie

## Enable distribution
-proto_dist inet_tcp

## Increase distribution buffer
+zdbbl 32768

Connecting Nodes

Cluster formation happens via Khepri/Ra. Use the API to join nodes:

%% On the joining node
erl_esdb:join_cluster(my_store, 'store1@192.168.1.10').
# Elixir
:erl_esdb.join_cluster(:my_store, :"store1@192.168.1.10")

Data Directory Guidelines

Linux/Production

Store data on separate disk partitions for performance:

{data_dir, "/bulk0/erl_esdb/my_store"}

Development

Use temp directory for ephemeral data:

{data_dir, "/tmp/erl_esdb/dev_store"}

Docker/Container

Mount a volume for persistence:

volumes:
  - esdb_data:/var/lib/erl_esdb
{data_dir, "/var/lib/erl_esdb/my_store"}

Performance Tuning

High-Write Workloads

config :erl_esdb,
  stores: [
    high_write: [
      writer_pool_size: 100,      # Many concurrent writers
      reader_pool_size: 20,       # Fewer readers needed
      mode: :cluster              # Distribute writes
    ]
  ],
  persistence_interval: 60_000    # Less frequent persistence

High-Read Workloads

config :erl_esdb,
  stores: [
    high_read: [
      writer_pool_size: 10,       # Fewer writers needed
      reader_pool_size: 200,      # Many concurrent readers
      mode: :cluster              # Read from any replica
    ]
  ],
  reader_idle_timeout_ms: 600_000 # Keep readers alive longer

Low-Latency Requirements

config :erl_esdb,
  stores: [
    low_latency: [
      timeout: 2_000,             # Fast timeouts
      gateway_pool_size: 10       # More gateway workers
    ]
  ],
  health_probe_interval: 1_000,   # Fast failure detection
  health_failure_threshold: 1     # Immediate failover

Telemetry Events

erl-esdb emits telemetry events for monitoring:

EventMeasurementsMetadata
[erl_esdb, append, start]-store_id, stream
[erl_esdb, append, stop]durationstore_id, stream, count
[erl_esdb, append, exception]durationstore_id, stream, reason
[erl_esdb, read, start]-store_id, stream
[erl_esdb, read, stop]durationstore_id, stream, count
[erl_esdb, read, exception]durationstore_id, stream, reason
[erl_esdb, health, probe]latencystore_id, node, status
[erl_esdb, health, change]-store_id, node, old, new

Attaching Handlers

# Elixir
:telemetry.attach_many(
  "erl-esdb-metrics",
  [
    [:erl_esdb, :append, :stop],
    [:erl_esdb, :read, :stop],
    [:erl_esdb, :health, :change]
  ],
  &MyApp.Metrics.handle_event/4,
  nil
)
%% Erlang
telemetry:attach_many(
  <<"erl-esdb-metrics">>,
  [
    [erl_esdb, append, stop],
    [erl_esdb, read, stop],
    [erl_esdb, health, change]
  ],
  fun my_metrics:handle_event/4,
  undefined
).

See Also