Skip to content

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 FallbackConfigProvider.

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 ConsulClient cannot be retrieved.

__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 ModifyIndex returned by Consul for this key. The request will block until the index changes.

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 ModifyIndex returned by Consul for this prefix. The request will block until the index changes.

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.