Foundation.ProcessRegistry (foundation v0.1.0)
Centralized process registry for Foundation layer.
Provides namespace isolation using Elixir's native Registry to enable concurrent testing and prevent naming conflicts between production and test environments.
Performance Characteristics
- Storage: ETS-based partitioned table for high concurrent throughput
- Partitions:
24
partitions (matches CPU cores) - Lookup Time: O(1) average case, < 1ms typical latency
- Registration: Atomic operations with automatic process monitoring
- Memory: Minimal overhead per registered process (~100 bytes)
Registry Architecture
Uses Elixir's native Registry module with optimized settings:
- Keys:
:unique
- Each {namespace, service} key maps to exactly one process - Partitioning: CPU-optimized for concurrent access patterns
- Monitoring: Automatic cleanup when processes terminate
- Fault Tolerance: ETS table survives individual process crashes
Supported Namespaces
:production
- For normal operation{:test, reference()}
- For test isolation with unique references
Examples
# Register a service in production
:ok = ProcessRegistry.register(:production, :config_server, self())
# Register in test namespace
test_ref = make_ref()
:ok = ProcessRegistry.register({:test, test_ref}, :config_server, self())
# Lookup services
{:ok, pid} = ProcessRegistry.lookup(:production, :config_server)
Summary
Functions
Child specification for supervision tree integration.
Cleanup all services in a test namespace.
Count the number of services in a namespace.
Get all registered services with their PIDs for a namespace.
List all services registered in a namespace.
Look up a service in the given namespace.
Register a service in the given namespace.
Check if a service is registered in a namespace.
Get registry statistics for monitoring and performance analysis.
Unregister a service from the given namespace.
Create a via tuple for GenServer registration.
Types
@type namespace() :: :production | {:test, reference()}
@type registry_key() :: {namespace(), service_name()}
@type service_name() ::
:config_server | :event_store | :telemetry_service | :test_supervisor
Functions
Child specification for supervision tree integration.
@spec cleanup_test_namespace(reference()) :: :ok
Cleanup all services in a test namespace.
This is useful for test cleanup - terminates all processes registered in the given test namespace.
Parameters
test_ref
: The test reference used in namespace
Returns
:ok
after cleanup is complete
Examples
iex> test_ref = make_ref()
iex> # ... register services in {:test, test_ref} ...
iex> ProcessRegistry.cleanup_test_namespace(test_ref)
:ok
@spec count_services(namespace()) :: non_neg_integer()
Count the number of services in a namespace.
Parameters
namespace
: The namespace to count services in
Returns
- Non-negative integer count of services
Examples
iex> ProcessRegistry.count_services(:production)
3
@spec get_all_services(namespace()) :: %{required(service_name()) => pid()}
Get all registered services with their PIDs for a namespace.
Parameters
namespace
: The namespace to get services for
Returns
- Map of service_name => pid
Examples
iex> ProcessRegistry.get_all_services(:production)
%{
config_server: #PID<0.123.0>,
event_store: #PID<0.124.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> ProcessRegistry.list_services(:production)
[:config_server, :event_store, :telemetry_service]
iex> ProcessRegistry.list_services({:test, test_ref})
[]
@spec lookup(namespace(), service_name()) :: {:ok, pid()} | :error
Look up a service in the given namespace.
Parameters
namespace
: The namespace to search inservice
: The service name to lookup
Returns
{:ok, pid}
if service found:error
if service not found
Examples
iex> ProcessRegistry.lookup(:production, :config_server)
{:ok, #PID<0.123.0>}
iex> ProcessRegistry.lookup(:production, :nonexistent)
:error
@spec register(namespace(), service_name(), pid()) :: :ok | {:error, {:already_registered, pid()}}
Register a service in the given namespace.
Parameters
namespace
: The namespace for service isolationservice
: The service name to registerpid
: The process PID to register
Returns
:ok
if registration succeeds{:error, {:already_registered, pid}}
if name already taken
Examples
iex> ProcessRegistry.register(:production, :config_server, self())
:ok
iex> ProcessRegistry.register(:production, :config_server, self())
{:error, {:already_registered, #PID<0.123.0>}}
@spec registered?(namespace(), service_name()) :: boolean()
Check if a service is registered in a namespace.
Parameters
namespace
: The namespace to checkservice
: The service name to check
Returns
true
if service is registeredfalse
if service is not registered
Examples
iex> ProcessRegistry.registered?(namespace, :config_server)
true
@spec stats() :: %{ total_services: non_neg_integer(), production_services: non_neg_integer(), test_namespaces: non_neg_integer(), partitions: pos_integer(), partition_count: pos_integer(), memory_usage_bytes: non_neg_integer(), ets_table_info: map() }
Get registry statistics for monitoring and performance analysis.
Returns
- Map with comprehensive registry statistics including:
- Service counts by namespace type
- Performance characteristics
- Memory usage information
- Partition utilization
Examples
iex> ProcessRegistry.stats()
%{
total_services: 15,
production_services: 3,
test_namespaces: 4,
partitions: 8,
partition_count: 8,
memory_usage_bytes: 4096,
ets_table_info: %{...}
}
@spec unregister(namespace(), service_name()) :: :ok
Unregister a service from the given namespace.
Note: This is typically not needed as Registry automatically unregisters when the process dies.
Parameters
namespace
: The namespace containing the serviceservice
: The service name to unregister
Returns
:ok
regardless of whether service was registered
Examples
iex> ProcessRegistry.unregister(:production, :config_server)
:ok
@spec via_tuple(namespace(), service_name()) :: {:via, Registry, {atom(), registry_key()}}
Create a via tuple for GenServer registration.
This is used in GenServer.start_link/3 for automatic registration.
Parameters
namespace
: The namespace for the serviceservice
: The service name
Returns
- Via tuple for GenServer registration
Examples
iex> via = ProcessRegistry.via_tuple(:production, :config_server)
iex> GenServer.start_link(MyServer, [], name: via)