Skip to content

Dependency Injection & Service Location

Overview

The athomic-docs project manages dependencies and object lifecycles without relying on an external dependency injection framework. Instead, it employs a robust and clear approach using a combination of two classic design patterns:

  1. The Facade Pattern: The Athomic class acts as a central service locator, providing a single, unified entry point to all core framework services.
  2. The Factory Pattern: Dedicated Factory classes are responsible for creating and managing singleton instances of specific components, handling their unique dependencies internally.

This approach promotes loose coupling, simplifies testing through easy mocking, and makes the flow of dependency resolution explicit and easy to follow.


The Athomic Façade

The main entry point to the entire framework is the nala.athomic.facade.Athomic class. During application startup, this class is instantiated once. Its constructor (__init__) is responsible for wiring together the primary, high-level services.

# From: nala.athomic.facade.py
class Athomic:
    def __init__(self, ...):
        # ...
        self.settings = settings or get_settings()
        self.secrets_manager = SecretsManager(self.settings)
        self.lifecycle_manager = LifecycleManager(...)
        self.tracer = get_tracer(__name__)
        self.plugin_manager: PluginManager = PluginManager()
        # ...

The nala.athomic.provider module then makes this single Athomic instance globally accessible via the get_athomic_instance() function, allowing any part of the application to access core services like the LifecycleManager or PluginManager when needed.


The Factory Pattern

For most components within the Athomic Layer, a dedicated factory is responsible for its creation. This pattern provides several key advantages:

  • Centralized Creation Logic: The logic for creating a complex object (e.g., a ConnectionManager that needs DatabaseSettings) is encapsulated in one place.
  • Singleton Management: Factories typically manage a singleton instance of the object they create, ensuring resources like connection pools are shared efficiently.
  • Simplified Dependency Injection: Components that need a dependency can simply call the factory's create() method without needing to know how to construct it.
  • Testability: Factories usually include a .clear() method, which is crucial for resetting state between tests and ensuring test isolation.

Example Flow

A great example is the MongoOutboxRepository. It needs a database connection to work. Here is how its dependencies are resolved:

  1. The application needs an OutboxStorageProtocol instance.
  2. It calls OutboxStorageFactory.create().
  3. The OutboxStorageFactory knows it needs a database connection. It calls connection_manager_factory.create().
  4. The ConnectionManagerFactory creates the singleton ConnectionManager.
  5. The OutboxStorageFactory then asks the ConnectionManager for the specific database connection (get_document_db(...)).
  6. Finally, it injects the database connection into a new MongoOutboxRepository instance and returns it.

This chain of factory calls ensures that dependencies are resolved correctly and only when needed.


API Reference

Core Façade and Provider

nala.athomic.facade.Athomic

A Facade that provides a single, simple entry point to all of Athomic's services.

This class acts as the main interaction point for an application utilizing the Athomic framework. It manages the initialization, dependency injection, and lifecycle of all infrastructure components, such as secrets management, plugins, and background services.

Attributes:

Name Type Description
settings AppSettings

The validated application settings.

secrets_manager SecretsManager

The manager responsible for resolving secrets.

lifecycle_manager LifecycleManager

The orchestrator for the service lifecycle.

plugin_manager PluginManager

The manager for the plugin system.

tracer Tracer

The OpenTelemetry Tracer instance for this component.

observability

A namespace for observability components like loggers.

__init__(domain_initializers_registrar=None, settings=None)

Initializes the Athomic layer.

Parameters:

Name Type Description Default
domain_initializers_registrar Optional[Callable[[], None]]

A function from the application layer (e.g., API) that registers all business domain-specific initializers.

None
settings Optional[AppSettings]

An instance of application settings. If not provided, it will be loaded globally. Ideal for dependency injection in tests.

None

shutdown() async

Runs the graceful shutdown sequence for all services.

startup() async

Runs the complete, ordered startup sequence for the application's infrastructure.

This method orchestrates the startup of services in the correct dependency order: 1. Resolves all secret references within the configuration. 2. Discovers and loads all available plugins. 3. Calls the 'on_athomic_startup' hook, allowing plugins to initialize. 4. Starts all registered services (e.g., database, messaging).

Raises:

Type Description
RuntimeError

If any critical step in the startup sequence fails.

nala.athomic.provider

clear_athomic_instance()

For use in tests, to ensure isolation.

get_athomic_instance()

Returns the singleton instance of the Athomic facade that has already been initialized.

Raises:

Type Description
RuntimeError

If the instance has not yet been created and set.

set_athomic_instance(instance)

Sets the global singleton instance of the Athomic facade. This function should be called ONLY ONCE during application startup.

Example Factories

nala.athomic.database.factory.ConnectionManagerFactory

Manages the singleton instance of the ConnectionManager. Ensures that only one instance of the ConnectionManager exists throughout the application's lifecycle.

clear() async

Clears the singleton instance of the ConnectionManager. This is primarily used for test isolation.

create(settings=None)

Creates and returns the singleton instance of the ConnectionManager.

On the first call, it instantiates the ConnectionManager. Subsequent calls return the cached instance.

nala.athomic.serializer.factory.SerializerFactory

Factory for instantiating message serializers based on messaging backend. Falls back to BaseSerializer if no specific implementation is registered. Caches instances by backend name for singleton-like behavior per backend.

clear() classmethod

Clears the singleton cache of serializer instances.

create(settings=None) classmethod

Creates and returns a singleton instance of the configured SerializerProtocol by delegating to a registered creator.