Dependency Injection with Dishka
Relevant source files
The following files were used as context for generating this wiki page:
The Athena project utilizes Dishka as its primary dependency injection (DI) framework to manage the composition graph and runtime wiring of the application. Dishka is responsible for constructing the object graph for the Starlette-based application, the taskiq-driven workers, and the testing environment, ensuring that components such as database engines, repositories, and services are correctly instantiated and provided to their respective consumers.
Sources: AGENTS.md:92-98, README.md:57-61
Composition Architecture
The DI system is structured into several layers of providers and scopes. The composition layer acts as the outer root of the application, importing concrete adapters, infrastructure, and repositories to wire the runtime graph.
Dependency Scopes
Athena uses specific Dishka scopes to manage the lifecycle of objects:
- APP Scope: Owns long-lived, global resources such as configuration, database engines, Valkey clients, taskiq brokers, and long-lived adapters.
- REQUEST Scope: Manages per-request dependencies, such as Unit of Work factories, which must not become global state.
Sources: AGENTS.md:100-112, tests/unit/composition/test_provider_replacement.py:73-74
Component Overview
| Component | Responsibility |
|---|---|
| Providers | Define how dependencies are created and registered within specific scopes. |
| Containers | Hold the instantiated objects and manage their lifecycle (startup/shutdown). |
| Lifespan | Integrates DI container initialization with the ASGI application lifecycle. |
| Overrides | Allow for replacing production dependencies with mocks or in-memory implementations during testing. |
Sources: src/osu_server/composition/lifespan.py:64-96, AGENTS.md:108-110
Implementation Flow
The application initializes the DI container during the Starlette lifespan startup. This process ensures that critical infrastructure is healthy before the application begins serving requests.
The diagram above illustrates the sequence of operations from application startup to shutdown, emphasizing the role of the DI container in resource management.
Sources: src/osu_server/composition/lifespan.py:64-96
Eager Validation
During startup, the application performs eager validation of essential APP-scope dependencies to catch configuration errors early. Verified dependencies include:
AppConfigAsyncEngine(SQLAlchemy)AsyncBroker(taskiq)httpx.AsyncClient- Various transport handlers (e.g.,
BanchoEndpoint,RegistrationHandler)
Sources: src/osu_server/composition/lifespan.py:27-37
Starlette Integration
Integration with the Starlette framework is achieved through starlette-dishka middleware and explicit lifespan management. The DI container is stored in app.state.dishka_container for access by the middleware and routing system.
Injection Mechanisms
Athena uses the @inject decorator and FromDishka type hints to resolve dependencies in route endpoints.
@inject
async def _injected_config_endpoint(
request: Request,
*,
config: FromDishka[AppConfig],
) -> PlainTextResponse:
_ = request
return PlainTextResponse(config.environment)
Sources: tests/unit/composition/test_starlette_lifecycle.py:46-52
Testing and Overrides
Athena supports explicit provider overrides for testing purposes. This allows developers to replace production infrastructure (like PostgreSQL) with in-memory implementations (like InMemorySessionStore) without branching production code on environment variables.
Override Rules
- Do not branch production providers on
config.environment == "test". - Use
TestProviderSetandreplace_valuehelper functions to define overrides. - Overrides are passed to
make_app_containerormake_worker_containerduring initialization.
Sources: AGENTS.md:108-110, tests/unit/composition/test_provider_replacement.py:73-81
Conclusion
The DI system with Dishka provides a robust mechanism for decoupling component construction from business logic in the Athena project. By utilizing distinct scopes and a strict lifespan management process, the system ensures resource integrity, facilitates testability through overrides, and enforces the project's layered modular monolith architecture.
Sources: AGENTS.md:92-112, README.md:57-61