Providers — Aquilia Documentation
Comprehensive guide and documentation for Providers in the Aquilia framework. View API reference, examples, and implementation patterns.
Dependency Injection / Providers DI Providers Providers encapsulate instantiation logic. Each provider represents a contract for creating concrete services. ClassProvider The default provider type. Instantiates a class by auto-resolving constructor dependencies via inspect.signature() and type hints. Supports Annotated[Type, Inject(...)] for tagged dependencies and the async_init() convention for post-construction async initialization. Dependency Extraction The container analyzes constructor signatures at manifest loading time to construct O(1) resolution plans: ))} from aquilia.di.providers import ClassProvider from aquilia.di import Inject from typing import Annotated class OrderService: def __init__( self, repo: OrderRepository, # Untagged dep cache: Annotated[CacheBackend, Inject(tag="redis")], # Tagged dep logger: Annotated[Logger, Inject(optional=True)], # Optional dep ): self.repo = repo self.cache = cache self.logger = logger async def async_init(self): """Called after __init__ if present. Perfect for async setup.""" await self.cache.ping() # Registers in container provider = ClassProvider(OrderService, scope="request") FactoryProvider Calls a sync or async factory function to create instances. Dependencies are auto-resolved from the factory function's parameter signature. from aquilia.di.providers import FactoryProvider async def create_database_pool(config: AppConfig) -> DatabasePool: pool = await asyncpg.create_pool(dsn=config.database_url) return pool provider = FactoryProvider( token=DatabasePool, factory_fn=create_database_pool, scope="app", ) ValueProvider Returns a pre-existing object instance. Useful for configurations or external clients initialized outside the DI framework. from aquilia.di.providers import ValueProvider config = AppConfig(debug=True) provider = ValueProvider(token=AppConfig, value=config) PoolProvider Maintains an internal `asyncio.Queue` pool of instances for concurrent reuse. Resolving acquires an instance, and releasing returns it. from aquilia.di.providers import PoolProvider # Pool manages 10 instances of heavy clients provider = PoolProvider( HeavyClient, max_size=10, scope="pooled", max_waiters=256, # fast-fail once 256 callers queue on an exhausted pool ) max_waiters (default None = unbounded) caps how many callers may queue against an exhausted pool. Beyond the cap, a burst fast-fails with DIResolutionFault instead of thundering-herd queueing. The process-wide default comes from the pool_max_waiters DI setting. ContractProvider Specially designed for request validation. Instantiates a Contract validation schema by parsing and binding the incoming request payload with strict casting rules. from aquilia.di.providers import ContractProvider # Registers in container container.register(ContractProvider(UserContract, scope="request")) AliasProvider Points one token at another — resolving the alias returns the target's instance. Use it to expose the same service under multiple names or to bind an interface token to a concrete registration. from aquilia.di.providers import AliasProvider # Resolving ILogger returns whatever is registered for StructuredLogger container.register(AliasProvider(token=ILogger, target_token=StructuredLogger)) LazyProxyProvider Returns a lazy proxy that defers resolution of its target until first attribute access — the tool for breaking an otherwise-illegal construction cycle. The proxy resolves synchronously on first touch and refuses to resolve inside a running event loop (deadlock guard). from aquilia.di.providers import LazyProxyProvider # ServiceA depends on LazyB; ServiceB is built on first access. container.register(LazyProxyProvider(token=LazyB, target_token=ServiceB)) See Patterns & Recipes → Lazy Resolution for the full cycle-breaking recipe. ScopedProvider A thin wrapper that re-labels an inner provider's scope — used internally to enforce request/ephemeral semantics on a provider without rewriting it. It copies the inner metadata and overrides only the scope, delegating instantiate and shutdown to the inner provider. from aquilia.di.providers import ScopedProvider, ClassProvider inner = ClassProvider(RequestTracker) # default "app" container.register(ScopedProvider(inner, scope="request")) Automatic Provider Selection When the Registry processes a manifest service entry, it selects the appropriate provider type automatically: Condition Provider Created ))} Container Scopes )
Go to Homepage