Packages
ex_esdb
0.3.3
0.11.0
0.10.0
0.9.0
0.8.0
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14-alpha
0.0.13-alpha
0.0.12-alpha
0.0.11-alpha
0.0.10-alpha
0.0.9-alpha
0.0.8-alpha
0.0.6-alpha
0.0.5-alpha
0.0.4-alpha
0.0.3-alpha
0.0.2-alfa
0.0.1-alfa
ExESDB is a reincarnation of rabbitmq/khepri, specialized for use as a BEAM-native event store.
Current section
Files
Jump to
Current section
Files
lib/ex_esdb/store_system.ex
defmodule ExESDB.StoreSystem do
@moduledoc """
Supervisor for store-related components.
This supervisor manages the store lifecycle and clustering components.
Uses :rest_for_one strategy to ensure proper startup order.
Startup order (critical for distributed coordination):
1. Store: Core store GenServer - must be fully operational first
2. StoreCluster: Clustering coordination - depends on Store being ready
3. StoreRegistry: Distributed store registry - starts after Store system is stable
This order ensures StoreRegistry only announces a store that is actually ready
to handle requests, preventing race conditions in distributed environments.
"""
use Supervisor
require Logger
alias ExESDB.Themes, as: Themes
alias ExESDB.StoreNaming
@impl true
def init(opts) do
Logger.info("[STORE_SYSTEM] Initializing StoreSystem supervisor with opts: #{inspect(opts)}")
Logger.info("[STORE_SYSTEM] StoreSystem PID: #{inspect(self())}, Node: #{inspect(node())}")
# Extract store_id for logging
store_id = StoreNaming.extract_store_id(opts)
Logger.info("[STORE_SYSTEM] Store ID: #{inspect(store_id)}")
Logger.info("[STORE_SYSTEM] Starting store components in critical dependency order...")
children = [
# Store must start first as other components depend on it
{ExESDB.Store, opts},
# StoreCluster handles clustering coordination and depends on Store
{ExESDB.StoreCluster, opts},
# StoreRegistry comes last - only starts after Store system is fully operational
{ExESDB.StoreRegistry, opts}
]
Logger.info("[STORE_SYSTEM] Configured #{length(children)} store subsystems:")
children |> Enum.with_index(1) |> Enum.each(fn {{module, _opts}, index} ->
Logger.info("[STORE_SYSTEM] #{index}. #{inspect(module)} - #{get_component_description(module)}")
end)
Logger.info("[STORE_SYSTEM] Using :rest_for_one strategy - each component depends on previous ones")
Logger.info("[STORE_SYSTEM] Max restarts: 5, Max seconds: 30")
IO.puts("#{Themes.system(self(), "StoreSystem is UP")}")
# Use :rest_for_one because each component depends on the previous ones
# StoreCluster depends on Store, StoreRegistry depends on both
result = Supervisor.init(children,
strategy: :rest_for_one,
max_restarts: 5,
max_seconds: 30
)
Logger.info("[STORE_SYSTEM] StoreSystem supervisor initialization complete")
result
end
defp get_component_description(ExESDB.Store), do: "Core Khepri store GenServer"
defp get_component_description(ExESDB.StoreCluster), do: "Clustering coordination and leadership"
defp get_component_description(ExESDB.StoreRegistry), do: "Distributed store registry and discovery"
defp get_component_description(_), do: "Store component"
def start_link(opts) do
store_id = StoreNaming.extract_store_id(opts)
name = StoreNaming.genserver_name(__MODULE__, store_id)
Supervisor.start_link(__MODULE__, opts, name: name)
end
def child_spec(opts) do
store_id = StoreNaming.extract_store_id(opts)
%{
id: StoreNaming.child_spec_id(__MODULE__, store_id),
start: {__MODULE__, :start_link, [opts]},
restart: :permanent,
shutdown: :infinity,
type: :supervisor
}
end
end