Event Store Discovery
Chronicle Elixir provides APIs to query information about available event stores and their namespaces from the Chronicle kernel. This is useful for administrative tasks, multi-tenant applications, and debugging. See Event Store and Namespaces for what these concepts mean and how they relate to multi-tenancy — this page covers the Elixir-specific discovery APIs for listing and verifying them at runtime.
Getting Event Stores
Section titled “Getting Event Stores”Query all event store names from the Chronicle kernel:
{:ok, stores} = Chronicle.get_event_stores()# => {:ok, ["my-app", "crm", "analytics"]}This is useful in multi-tenant or multi-application scenarios where you need to discover which event stores are available:
case Chronicle.get_event_stores() do {:ok, stores} -> IO.puts("Available event stores: #{inspect(stores)}") {:error, reason} -> IO.puts("Failed to get event stores: #{inspect(reason)}")endGetting Namespaces
Section titled “Getting Namespaces”Query all namespaces within an event store:
# Use the configured client's event store{:ok, namespaces} = Chronicle.get_namespaces()# => {:ok, ["tenant-1", "tenant-2", "tenant-3"]}
# Specify a different event store{:ok, namespaces} = Chronicle.get_namespaces(event_store: "analytics")This is especially useful in multi-tenant applications:
defmodule MyApp.Tenants do def list_all_tenants() do case Chronicle.get_namespaces() do {:ok, tenant_ids} -> tenant_ids {:error, _} -> [] end end
def migrate_all_tenants(migration_func) do Enum.each(list_all_tenants(), fn tenant_id -> IO.puts("Migrating tenant: #{tenant_id}") migration_func.(tenant_id) end) endendTypical Usage
Section titled “Typical Usage”Multi-Tenant Admin Interface
Section titled “Multi-Tenant Admin Interface”defmodule MyApp.Admin.Dashboard do alias MyApp.Tenants
def get_system_stats() do with {:ok, stores} <- Chronicle.get_event_stores(), {:ok, namespaces} <- Chronicle.get_namespaces() do %{ event_stores: stores, current_store_namespaces: namespaces, total_tenants: Enum.count(namespaces) } else {:error, reason} -> {:error, reason} end end
def list_tenant_info() do with {:ok, tenant_ids} <- Chronicle.get_namespaces() do Enum.map(tenant_ids, fn tenant_id -> %{ id: tenant_id, event_store: "my-app", namespace: tenant_id } end) else {:error, reason} -> {:error, reason} end endendVerifying Environment Before Operations
Section titled “Verifying Environment Before Operations”defmodule MyApp.Operations do def safe_append(tenant_id, event) do with {:ok, namespaces} <- Chronicle.get_namespaces() do if Enum.member?(namespaces, tenant_id) do Chronicle.append("entity-123", event, namespace: tenant_id) else {:error, :tenant_not_found} end end end
def safe_read(tenant_id, entity_id) do with {:ok, namespaces} <- Chronicle.get_namespaces() do if Enum.member?(namespaces, tenant_id) do Chronicle.read_model(MyApp.ReadModels.Entity, entity_id, namespace: tenant_id) else {:error, :tenant_not_found} end end endendMulti-Store Operations
Section titled “Multi-Store Operations”defmodule MyApp.MultiStore do def list_all_entities() do with {:ok, stores} <- Chronicle.get_event_stores() do Enum.flat_map(stores, fn store_name -> case Chronicle.all(MyApp.ReadModels.Entity, client: store_name) do {:ok, entities} -> entities {:error, _} -> [] end end) else {:error, _} -> [] end end
def get_global_stats() do with {:ok, stores} <- Chronicle.get_event_stores() do Enum.map(stores, fn store_name -> with {:ok, namespaces} <- Chronicle.get_namespaces(event_store: store_name) do %{ store: store_name, namespace_count: Enum.count(namespaces), namespaces: namespaces } else {:error, reason} -> %{store: store_name, error: reason} end end) end endendOptions
Section titled “Options”Both get_event_stores/1 and get_namespaces/1 accept options:
:client— the client name (default:Chronicle.Client):event_store— forget_namespaces/1, the event store to query (defaults to the configured client’s event store)
# Use a named clientChronicle.get_event_stores(client: :my_app_client)
# Query a specific event store's namespacesChronicle.get_namespaces(event_store: "crm")
# BothChronicle.get_namespaces(client: :analytics, event_store: "analytics")Error Handling
Section titled “Error Handling”Both functions return {:ok, list} on success or {:error, reason} on failure:
case Chronicle.get_namespaces() do {:ok, namespaces} -> IO.puts("Namespaces: #{inspect(namespaces)}") {:error, reason} -> case reason do :no_client -> IO.puts("Chronicle.Client not started") _ -> IO.puts("Error: #{inspect(reason)}") endendSee Also
Section titled “See Also”Chronicle.EventStores— low-level event store discoveryChronicle— high-level APIREADME.md— quick start guide- Configuration options in
Chronicle.Client - Event Store and Namespaces — the shared concepts behind event stores and namespace-scoped tenancy