Service Discovery
Overview
The Service Discovery module provides a mechanism for services to find and communicate with each other in a dynamic, distributed environment. Instead of hardcoding IP addresses or hostnames, services register themselves with a central registry (like HashiCorp Consul) and query it to discover the locations of other services.
This is a fundamental pattern for building scalable and resilient microservice architectures. Athomic uses this module primarily for the Distributed Workload Sharding pattern.
How It Works
The ServiceDiscoveryProtocol defines the contract for any provider, with register, deregister, and discover methods. The ConsulDiscoveryProvider is the default implementation.
At startup, a service instance calls discovery_service.register_self(), which registers its service name, instance ID, and address with Consul. On shutdown, it calls deregister_self(). Other services can then call discovery_service.discover("service-name") to get a list of all healthy, active instances of that service.
API Reference
nala.athomic.integration.discovery.protocol.ServiceDiscoveryProtocol
Bases: Protocol
Defines the abstract contract for any service discovery provider.
This protocol adheres to the Dependency Inversion Principle (DIP), decoupling service consumers (like the Sharding or HTTP Client modules) from the concrete implementation (e.g., Consul, ZooKeeper).
deregister(service_id)
async
Removes this service instance from the discovery provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_id
|
str
|
The unique ID of the service instance to deregister. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if deregistration was successful. |
discover(name)
async
Discovers all healthy instances of a service by its logical name.
The provider should only return services that have a passing health check.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The logical name of the service to discover. |
required |
Returns:
| Type | Description |
|---|---|
List[Dict[str, Any]]
|
List[Dict[str, Any]]: A list of dictionaries, where each dictionary represents a healthy service instance (containing address, port, etc.). |
register(name, service_id, port, address=None, tags=None, health_check=None)
async
Registers the current service instance with the discovery provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The logical name of the service (e.g., "user-service"). |
required |
service_id
|
str
|
A unique ID for this specific instance of the service. |
required |
port
|
int
|
The port on which the service is running. |
required |
address
|
Optional[str]
|
The address of the service. If None, the agent's address is used. |
None
|
tags
|
Optional[List[str]]
|
A list of tags to associate with the service. |
None
|
health_check
|
Optional[Dict[str, Any]]
|
A dictionary defining a health check (e.g., HTTP, TCP, TTL). |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if registration was successful, False otherwise. |
nala.athomic.integration.discovery.providers.consul_provider.ConsulDiscoveryProvider
Bases: ServiceDiscoveryProtocol
Service Discovery implementation using HashiCorp Consul as the backend.
This provider fulfills the ServiceDiscoveryProtocol contract by delegating
I/O operations (register, deregister, discover) to the central, lifecycle-managed
ConsulClient instance. All operations are wrapped for resilience via
@cancellable_operation.
Attributes:
| Name | Type | Description |
|---|---|---|
settings |
DiscoverySettings
|
The service discovery configuration. |
consul_client |
ConsulClient
|
The shared, active Consul client instance. |
__init__(settings=None, consul_client=None)
Initializes the provider, resolving the shared ConsulClient dependency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[DiscoverySettings]
|
Configuration for the discovery module. |
None
|
consul_client
|
Optional[ConsulClient]
|
Optional injected Consul client instance for testing. |
None
|
deregister(service_id)
async
Removes the service instance from the Consul agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_id
|
str
|
The unique ID of the service instance to deregister. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if deregistration was successful. |
discover(name)
async
Discovers all currently healthy instances of a service by its logical name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The logical name of the service to discover. |
required |
Returns:
| Type | Description |
|---|---|
List[Dict[str, Any]]
|
List[Dict[str, Any]]: A list of dictionaries, each representing a healthy service instance. |
register(name, service_id, port, address=None, tags=None, health_check=None)
async
Registers the current service instance with the Consul agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The logical name of the service (e.g., "user-service"). |
required |
service_id
|
str
|
A unique ID for this specific service instance. |
required |
port
|
int
|
The port on which the service is running. |
required |
address
|
Optional[str]
|
The routable address of the service. |
None
|
tags
|
Optional[List[str]]
|
A list of tags for categorization. |
None
|
health_check
|
Optional[Dict[str, Any]]
|
A dictionary defining a health check. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if registration was successful, False otherwise. |