Skip to content

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

  1. 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.updated event on the internal event bus with the key and the new value.
  2. LiveConfigService: This service subscribes to the config.updated event. 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.

  3. LiveConfigModel: Your Pydantic settings models can inherit from LiveConfigModel. When you access an attribute on such a model, it automatically intercepts the call and queries the LiveConfigService for 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:

  1. Via Configuration File (settings.toml): In the TOML section for your schema, add a _live_keys_config map: toml [my_module] _live_keys_config = { pydantic_attr_name = "live.config.key" } PYDANTIC_ATTR_NAME = "static_default"

  2. Via Code (model_config): In the Pydantic schema class, define a live_keys dictionary in model_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 _live_keys_config section in the TOML configuration file.

__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 _live_keys_config metadata key.

{}