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

lookup_result()

@type lookup_result() :: {:ok, pid()} | {:error, Foundation.Types.Error.t()}

namespace()

@type namespace() :: :production | {:test, reference()}

registration_result()

@type registration_result() :: :ok | {:error, {:already_registered, pid()}}

service_name()

@type service_name() ::
  :config_server | :event_store | :telemetry_service | :test_supervisor

Functions

cleanup_test_namespace(test_ref)

@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

get_service_info(namespace)

@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
}

health_check(namespace, service, opts \\ [])

@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 check
  • service: The service name to check
  • opts: 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>}

list_services(namespace)

@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]

lookup(namespace, 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 in
  • service: 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}

Examples

{:ok, pid} = ServiceRegistry.lookup(:production, :config_server)
{:error, %Error{}} = ServiceRegistry.lookup(:production, :nonexistent)

register(namespace, service, pid)

@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 isolation
  • service: The service name to register
  • pid: 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>}}

unregister(namespace, service)

@spec unregister(namespace(), service_name()) :: :ok

Safely unregister a service from the given namespace.

Parameters

  • namespace: The namespace containing the service
  • service: The service name to unregister

Returns

  • :ok regardless of whether service was registered

Examples

iex> ServiceRegistry.unregister(:production, :config_server)
:ok

via_tuple(namespace, service)

@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 service
  • service: The service name

Returns

  • Via tuple for GenServer registration

wait_for_service(namespace, service, timeout \\ 5000)

@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 monitor
  • service: The service name to wait for
  • timeout: 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>}