CounterEx.Keeper (CounterEx v0.2.0)

View Source

GenServer that manages counter storage using pluggable backends.

The Keeper provides a singleton interface to counter operations, delegating to the configured backend (ETS, Atomics, or Counters).

Configuration

The backend is selected at startup via options:

# Use ETS backend (default)
CounterEx.Keeper.start_link(backend: CounterEx.Backend.ETS)

# Use Atomics backend with custom capacity
CounterEx.Keeper.start_link(
  backend: CounterEx.Backend.Atomics,
  backend_opts: [capacity: 10_000]
)

# Use Counters backend
CounterEx.Keeper.start_link(backend: CounterEx.Backend.Counters)

Sweep Functionality

The Keeper optionally supports periodic sweeping (clearing all counters):

# Clear all counters every 60 seconds
CounterEx.Keeper.start_link(interval: 60_000)

Summary

Functions

Returns a specification to start this module under a supervisor.

Delete a counter in the given namespace.

Delete all counters in the given namespace.

Get all counters in the given namespace.

Get the value of a counter in the given namespace.

Increment a counter in the given namespace.

Get backend information.

Initialize the Keeper with the selected backend.

Reset a counter to an initial value in the given namespace.

Set a counter to a specific value in the given namespace.

Start the Keeper GenServer.

Stop the Keeper GenServer.

Types

t()

@type t() :: %CounterEx.Keeper{
  backend_module: module(),
  backend_state: term(),
  interval: pos_integer() | nil
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

compare_and_swap(server \\ __MODULE__, namespace, key, expected, new_value)

@spec compare_and_swap(
  GenServer.server(),
  CounterEx.Backend.namespace(),
  CounterEx.Backend.key(),
  integer(),
  integer()
) :: {:ok, integer()} | {:error, :mismatch, integer()} | {:error, term()}

Compare-and-swap operation.

delete(server \\ __MODULE__, namespace, key)

@spec delete(
  GenServer.server(),
  CounterEx.Backend.namespace(),
  CounterEx.Backend.key()
) ::
  :ok | {:error, term()}

Delete a counter in the given namespace.

delete_namespace(server \\ __MODULE__, namespace)

@spec delete_namespace(GenServer.server(), CounterEx.Backend.namespace()) ::
  :ok | {:error, term()}

Delete all counters in the given namespace.

get_all_values(server \\ __MODULE__, namespace)

@spec get_all_values(GenServer.server(), CounterEx.Backend.namespace()) ::
  {:ok, %{required(CounterEx.Backend.key()) => integer()}} | {:error, term()}

Get all counters in the given namespace.

get_value(server \\ __MODULE__, namespace, key)

@spec get_value(
  GenServer.server(),
  CounterEx.Backend.namespace(),
  CounterEx.Backend.key()
) ::
  {:ok, integer() | nil} | {:error, term()}

Get the value of a counter in the given namespace.

increment(server \\ __MODULE__, namespace, key, step, default)

@spec increment(
  GenServer.server(),
  CounterEx.Backend.namespace(),
  CounterEx.Backend.key(),
  integer(),
  integer()
) :: {:ok, integer()} | {:error, term()}

Increment a counter in the given namespace.

info(server \\ __MODULE__)

@spec info(GenServer.server()) :: {:ok, map()} | {:error, term()}

Get backend information.

init(opts)

Initialize the Keeper with the selected backend.

reset(server \\ __MODULE__, namespace, key, initial_value \\ 0)

@spec reset(
  GenServer.server(),
  CounterEx.Backend.namespace(),
  CounterEx.Backend.key(),
  integer()
) ::
  {:ok, integer()} | {:error, term()}

Reset a counter to an initial value in the given namespace.

set(server \\ __MODULE__, namespace, key, value)

@spec set(
  GenServer.server(),
  CounterEx.Backend.namespace(),
  CounterEx.Backend.key(),
  integer()
) ::
  {:ok, integer()} | {:error, term()}

Set a counter to a specific value in the given namespace.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Start the Keeper GenServer.

Options

  • :backend - Backend module (default: CounterEx.Backend.ETS)
  • :backend_opts - Options passed to backend init (default: [])
  • :interval - Sweep interval in milliseconds (default: nil - no sweeping)
  • :name - GenServer name (default: __MODULE__)

Examples

# Start with ETS backend
{:ok, pid} = CounterEx.Keeper.start_link()

# Start with Atomics backend
{:ok, pid} = CounterEx.Keeper.start_link(
  backend: CounterEx.Backend.Atomics,
  backend_opts: [capacity: 5000]
)

# Start with periodic sweep
{:ok, pid} = CounterEx.Keeper.start_link(interval: 30_000)

stop(server \\ __MODULE__)

@spec stop(GenServer.server()) :: :ok

Stop the Keeper GenServer.