Dynamic Configuration Providers
Overview
The Dynamic Configuration Providers module contains the client-side logic for fetching configuration values from external, centralized sources like HashiCorp Consul's Key-Value (KV) store. This is the engine that powers the Live Configuration feature.
Key Features
- Provider-Based: Built on a protocol, allowing for different backends to be supported.
- Resilient Fallback: Can be configured with a chain of providers. If the primary provider (e.g., Consul) is unavailable, it can fall back to a secondary one.
- Long Polling: Efficiently watches for changes using long-polling HTTP requests, enabling near real-time configuration updates.
How It Works
The ConfigurationProviderFactory creates a singleton instance of the configured provider. The primary implementation, ConsulConfigProvider, uses the shared ConsulClient to interact with the Consul KV API.
This provider is primarily consumed by the ConfigWatcherService, which uses its watch_prefix method to monitor for changes and publish update events to the internal event bus.
API Reference
nala.athomic.integration.config_providers.protocol.ConfigProvidersProtocol
Bases: Protocol
Defines the contract for any remote/dynamic configuration provider.
Implementations will handle fetching configuration values from external sources like Consul, Vault, or other configuration services.
get(key, default=None)
async
Fetches a configuration value for a given key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The identifier of the configuration value to fetch. |
required |
default
|
Optional[Any]
|
The default value to return if the key is not found or if the provider is unavailable. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The configuration value, which could be a string, number, dict, or list. |
watch(key, last_known_index=0)
async
Watches a key for changes using long polling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to watch. |
required |
last_known_index
|
int
|
The last known 'ModifyIndex' from Consul for this key. |
0
|
Returns:
| Type | Description |
|---|---|
int
|
A tuple containing (new_index, new_value). |
Any
|
The call will block until there is a change or a timeout occurs. |
watch_prefix(prefix, last_known_index=0)
async
Watches a key prefix for any changes recursively using long polling.
Returns:
| Type | Description |
|---|---|
int
|
A tuple containing (new_index, list_of_changed_items). |
Optional[List[Dict[str, Any]]]
|
Each item in the list is a dictionary like {'Key': ..., 'Value': ...}. |
nala.athomic.integration.config_providers.factory.ConfigurationProviderFactory
Factory for the singleton instance of the dynamic configuration provider.
This factory is responsible for building and providing a singleton instance
of the ConfigProvidersProtocol. It intelligently assembles the provider
based on the application's configuration. If a single provider is
configured, it creates a direct instance. If multiple providers are
configured, it creates a FallbackConfigProvider that wraps them in a
resilient chain.
clear()
classmethod
Clears the cached singleton instance. Useful for tests.
create(settings=None)
classmethod
Creates or retrieves the singleton instance of the configuration provider.
This method orchestrates the creation of the dynamic configuration
provider. It reads the settings, determines if a single provider or a
fallback chain is needed, and uses the config_provider_registry to
instantiate the appropriate provider class(es). The created instance
is cached for subsequent calls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[ConfigurationSettings]
|
The configuration for the dynamic providers. If None, global settings are used. |
None
|
Returns:
| Type | Description |
|---|---|
ConfigProvidersProtocol
|
A fully configured configuration provider instance, which may be |
ConfigProvidersProtocol
|
a single provider or a |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no providers are configured or if a configured backend name is not found in the registry. |
nala.athomic.integration.config_providers.providers.consul_provider.ConsulConfigProvider
Bases: ConfigProvidersProtocol
Fetches configuration values from Consul's Key-Value store.
This class implements the ConfigProvidersProtocol to provide dynamic
configuration values from a HashiCorp Consul KV backend. It uses the
application's central, lifecycle-managed ConsulClient for all
interactions with the Consul agent. It supports fetching single keys and
long-polling for changes on keys or prefixes.
Attributes:
| Name | Type | Description |
|---|---|---|
settings |
ConsulSettings
|
The configuration for connecting to the Consul agent. |
consul_client
property
Lazily resolves and returns the shared ConsulClient instance.
This ensures that the client is only fetched when needed and that it's the same instance managed by the application's lifecycle.
Returns:
| Type | Description |
|---|---|
ConsulClient
|
The shared, application-wide Consul client instance. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If a valid |
__init__(settings=None, consul_client=None)
Initializes the ConsulConfigProvider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[ConsulSettings]
|
The Consul connection settings. |
None
|
consul_client
|
Optional[ConsulClient]
|
An optional, pre-initialized Consul client, primarily for testing and dependency injection. |
None
|
get(key, default=None)
async
Fetches a configuration value for a given key from Consul.
It safely handles connection issues by returning the default value. It attempts to parse the retrieved value as JSON, falling back to a plain string if parsing fails.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The identifier of the configuration value to fetch. |
required |
default
|
Optional[Any]
|
The value to return if the key is not found or if the provider is unavailable. |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
The parsed configuration value or the provided default. |
watch(key, last_known_index=0)
async
Watches a single key in Consul for changes using long-polling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The key to watch. |
required |
last_known_index
|
int
|
The last |
0
|
Returns:
| Type | Description |
|---|---|
int
|
A tuple containing the new index and the new value. The value is |
Any
|
None if the key was deleted or not found. |
watch_prefix(prefix, last_known_index=0)
async
Watches a key prefix recursively in Consul for changes using long-polling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix
|
str
|
The key prefix (folder) to watch. |
required |
last_known_index
|
int
|
The last |
0
|
Returns:
| Type | Description |
|---|---|
int
|
A tuple containing the new index and a list of all key-value |
Optional[List[Dict[str, Any]]]
|
data under the prefix. |