Foundation.ServiceRegistry (foundation v0.1.0)
High-level service registration API for Foundation layer.
Provides a clean interface for service registration and discovery, wrapping the lower-level ProcessRegistry with error handling, logging, and convenience functions.
Examples
# Register a service
:ok = ServiceRegistry.register(:production, :config_server, self())
# Lookup a service
{:ok, pid} = ServiceRegistry.lookup(:production, :config_server)
# List services in a namespace
[:config_server, :event_store] = ServiceRegistry.list_services(:production)
Summary
Functions
Cleanup services in a test namespace with detailed logging.
Get comprehensive service information for a namespace.
Check if a service is available and healthy in a namespace.
List all services registered in a namespace.
Lookup a service with optional error handling and telemetry.
Register a service in the given namespace with error handling and logging.
Safely unregister a service from the given namespace.
Create a via tuple for service registration.
Wait for a service to become available in a namespace.
Types
@type lookup_result() :: {:ok, pid()} | {:error, Foundation.Types.Error.t()}
@type namespace() :: :production | {:test, reference()}
@type registration_result() :: :ok | {:error, {:already_registered, pid()}}
@type service_name() ::
:config_server | :event_store | :telemetry_service | :test_supervisor
Functions
@spec cleanup_test_namespace(reference()) :: :ok
Cleanup services in a test namespace with detailed logging.
Parameters
test_ref
: The test reference used in namespace
Returns
:ok
after cleanup is complete
Examples
iex> test_ref = make_ref()
iex> ServiceRegistry.cleanup_test_namespace(test_ref)
:ok
@spec get_service_info(namespace()) :: %{ namespace: namespace(), services: map(), total_services: non_neg_integer(), healthy_services: non_neg_integer() }
Get comprehensive service information for a namespace.
Parameters
namespace
: The namespace to analyze
Returns
- Map with detailed service information
Examples
iex> ServiceRegistry.get_service_info(:production)
%{
namespace: :production,
services: %{
config_server: %{pid: #PID<0.123.0>, alive: true, uptime_ms: 12345},
event_store: %{pid: #PID<0.124.0>, alive: true, uptime_ms: 12344}
},
total_services: 2,
healthy_services: 2
}
@spec health_check(namespace(), service_name(), keyword()) :: {:ok, pid()} | {:error, :health_check_timeout | :process_dead | {:health_check_crashed, term()} | {:health_check_error, term()} | {:health_check_failed, term()} | Foundation.Types.Error.t()}
Check if a service is available and healthy in a namespace.
This goes beyond simple registration checking - it verifies the process is alive and optionally calls a health check.
Parameters
namespace
: The namespace to checkservice
: The service name to checkopts
: Options for health checking
Options
:health_check
- Function to call for health verification:timeout
- Timeout for health check (default: 5000ms)
Returns
{:ok, pid}
if service is healthy{:error, reason}
if service is unhealthy or not found
Examples
iex> ServiceRegistry.health_check(:production, :config_server)
{:ok, #PID<0.123.0>}
iex> ServiceRegistry.health_check(:production, :config_server,
...> health_check: fn pid -> GenServer.call(pid, :health) end)
{:ok, #PID<0.123.0>}
@spec list_services(namespace()) :: [service_name()]
List all services registered in a namespace.
Parameters
namespace
: The namespace to list services for
Returns
- List of service names registered in the namespace
Examples
iex> ServiceRegistry.list_services(:production)
[:config_server, :event_store, :telemetry_service]
@spec lookup(namespace(), service_name()) :: lookup_result()
Lookup a service with optional error handling and telemetry.
Includes telemetry events for monitoring Registry performance and usage patterns.
Parameters
namespace
: The namespace to search inservice
: The service name to lookup
Returns
{:ok, pid()}
if service is found and healthy{:error, Error.t()}
if service not found or unhealthy
Telemetry Events
[:foundation, :foundation, :registry, :lookup]
- Emitted for all lookup operations- Measurements:
%{duration: integer()}
(in native time units) Metadata:
%{namespace: term(), service: atom(), result: :ok | :error}
- Measurements:
Examples
{:ok, pid} = ServiceRegistry.lookup(:production, :config_server)
{:error, %Error{}} = ServiceRegistry.lookup(:production, :nonexistent)
@spec register(namespace(), service_name(), pid()) :: registration_result()
Register a service in the given namespace with error handling and logging.
Parameters
namespace
: The namespace for service isolationservice
: The service name to registerpid
: The process PID to register
Returns
:ok
if registration succeeds{:error, reason}
if registration fails
Examples
iex> ServiceRegistry.register(:production, :config_server, self())
:ok
iex> ServiceRegistry.register(:production, :config_server, self())
{:error, {:already_registered, #PID<0.123.0>}}
@spec unregister(namespace(), service_name()) :: :ok
Safely unregister a service from the given namespace.
Parameters
namespace
: The namespace containing the serviceservice
: The service name to unregister
Returns
:ok
regardless of whether service was registered
Examples
iex> ServiceRegistry.unregister(:production, :config_server)
:ok
@spec via_tuple(namespace(), service_name()) :: {:via, Registry, {Foundation.ProcessRegistry, {namespace(), service_name()}}}
Create a via tuple for service registration.
Convenience wrapper around ProcessRegistry.via_tuple/2.
Parameters
namespace
: The namespace for the serviceservice
: The service name
Returns
- Via tuple for GenServer registration
@spec wait_for_service(namespace(), service_name(), pos_integer()) :: {:ok, pid()} | {:error, :timeout}
Wait for a service to become available in a namespace.
Parameters
namespace
: The namespace to monitorservice
: The service name to wait fortimeout
: Maximum time to wait in milliseconds (default: 5000)
Returns
{:ok, pid}
if service becomes available{:error, :timeout}
if timeout is reached
Examples
iex> ServiceRegistry.wait_for_service(:production, :config_server, 1000)
{:ok, #PID<0.123.0>}