Live Configuration (Hot-Reloading)
Overview
The Live Configuration system provides a powerful mechanism to change application settings at runtime without requiring a restart or deployment. This is a critical feature for operational agility, allowing you to tune parameters, toggle features, or respond to incidents in real-time.
Key Features
- Dynamic Updates: Settings can be changed in a central source (like Consul KV) and are automatically reflected in the application.
- Seamless Integration: Works through a special Pydantic model,
LiveConfigModel, which makes accessing dynamic values transparent to the developer. - Event-Driven: Uses the internal Event Bus for efficient, decoupled communication between the watcher and the state service.
How It Works: A Two-Part System
-
ConfigWatcherService: This is a background service that continuously long-polls an external configuration provider (e.g., Consul) for changes under a specific key prefix.- When a change is detected, it compares the new values with its last known state.
- For each key that has changed, it publishes a
config.updatedevent on the internal event bus with the key and the new value.
-
LiveConfigService: This service subscribes to theconfig.updatedevent. It maintains an in-memory, flattened dictionary of the application's most current configuration state. When it receives an update event, it updates its internal state. -
LiveConfigModel: Your Pydantic settings models can inherit fromLiveConfigModel. When you access an attribute on such a model, it automatically intercepts the call and queries theLiveConfigServicefor the latest value, falling back to the statically configured value if none is found.
API Reference
nala.athomic.control.live_config.service.LiveConfigService
Bases: BaseService
Maintains the current state of the application's live configuration.
This service acts as an in-memory cache for configuration values that can be
updated at runtime. It subscribes to internal config.updated events, which
are published by the ConfigWatcherService, and updates its internal state
accordingly. Other components, like LiveConfigModel, query this service
to get the most up-to-date configuration values.
Attributes:
| Name | Type | Description |
|---|---|---|
event_bus |
EventBusProtocol
|
The internal event bus used to receive update notifications. |
_config_state |
Dict[str, Any]
|
The in-memory dictionary holding the flattened, most current configuration state. |
__init__(settings=None, event_bus=None)
Initializes the LiveConfigService.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[LiveConfigSettings]
|
The configuration for the live config system. If not provided, global settings are used. |
None
|
event_bus
|
Optional[EventBusProtocol]
|
An instance of the event bus. If not provided, the global instance is retrieved. |
None
|
get(key, default=None)
Gets the latest value of a configuration key from the in-memory state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
The configuration key in flattened format (e.g., 'resilience.retry.attempts'). |
required |
default
|
Optional[Any]
|
The value to return if the key is not found. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Any |
Any
|
The current configuration value or the default. |
nala.athomic.control.live_config.watcher_service.ConfigWatcherService
Bases: BaseService
Watches a configuration prefix in an external provider for changes.
This background service actively monitors a specified key prefix in a
dynamic configuration backend (e.g., Consul KV). When it detects a change,
it compares the new values with its last known state and publishes
config.updated events on the internal event bus for each changed key.
Attributes:
| Name | Type | Description |
|---|---|---|
settings |
LiveConfigSettings
|
The settings for the live config system. |
config_provider |
ConfigProvidersProtocol
|
The client for the external configuration source. |
event_bus |
EventBusProtocol
|
The internal event bus for publishing updates. |
__init__(settings=None, config_provider=None, event_bus=None)
Initializes the ConfigWatcherService.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
settings
|
Optional[LiveConfigSettings]
|
The configuration for the live config system. |
None
|
config_provider
|
Optional[ConfigProvidersProtocol]
|
The provider for the external configuration source. |
None
|
event_bus
|
Optional[EventBusProtocol]
|
The internal event bus for publishing updates. |
None
|
nala.athomic.config.schemas.live.LiveConfigModel
Bases: BaseModel
A Pydantic BaseModel that provides transparent dynamic configuration.
Subclasses of LiveConfigModel can have their attributes updated at runtime.
When an attribute is accessed, this class intercepts the call and attempts
to fetch the latest value from the central LiveConfigService. This enables
hot-reloading of configuration without an application restart.
The mapping of dynamic fields is controlled in two ways, with configuration from files taking precedence:
-
Via Configuration File (
settings.toml): In the TOML section for your schema, add a_live_keys_configmap:toml [my_module] _live_keys_config = { pydantic_attr_name = "live.config.key" } PYDANTIC_ATTR_NAME = "static_default" -
Via Code (
model_config): In the Pydantic schema class, define alive_keysdictionary inmodel_config.
Attributes:
| Name | Type | Description |
|---|---|---|
_instance_live_keys |
Dict[str, str]
|
A dictionary mapping attribute
names in this model to their corresponding keys in the live
configuration backend. This map is populated from the
|
__getattribute__(name)
Overrides attribute access to fetch dynamic values from the live config service.
This method implements the core logic for live configuration:
1. Retrieves the static value (loaded at application startup).
2. Checks if the requested attribute is mapped as a "live key".
3. If it is, queries the LiveConfigService for the most up-to-date value.
4. Returns the live value if found; otherwise, the static value is used
as a fallback.
5. If the attribute is not a live key, the static value is returned directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the attribute being accessed. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Any |
Any
|
The latest value of the attribute from the live config service, |
Any
|
or the statically configured value as a fallback. |
__init__(**data)
Initializes the model and extracts the live key mapping.
This constructor intercepts the _live_keys_config dictionary from
the incoming data before passing the rest to the standard Pydantic
validator. This allows the model to store the live configuration
mapping without treating it as a standard model field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**data
|
Any
|
The raw data dictionary used to populate the model,
which may include the |
{}
|