Service Lifetimes¶
Wireup manages how long service instances live through three different lifetimes: Singleton, Scoped, and Transient. Configure the lifetime using the lifetime
parameter in the @service
decorator.
Available Lifetimes¶
Singleton (Default)¶
One instance is created and shared across the entire application.
@service # lifetime="singleton" is the default
class Database: ...
# Same instance everywhere
db1 = container.get(Database)
db2 = container.get(Database)
assert db1 is db2
Best for:
- Stateful services.
- Resource-intensive services.
- Configuration holders.
Scoped¶
One instance per scope, shared within that scope.
@service(lifetime="scoped")
class RequestContext: ...
with container.enter_scope() as scope1, container.enter_scope() as scope2:
# Same instance within scope
ctx1 = scope1.get(RequestContext)
ctx2 = scope1.get(RequestContext)
assert ctx1 is ctx2
# Different instance in different scope
other = scope2.get(RequestContext)
assert ctx1 is not other
Best for:
- Request-specific services.
- Per-operation state.
- Database transactions.
Info
Wireup integrations manage the scope lifecycle for you.
A new scope is entered at the beginning of a request and exited at the end.
This means that a scoped
service will live for the duration of the request.
The Wireup @wireup.inject_from_container(container)
decorator can also enter/exit a scope after the decorated function returns.
Learn More.
Transient¶
New instance created on every request.
@service(lifetime="transient")
class MessageBuilder: ...
with container.enter_scope() as scope:
# New instance every time
builder1 = scope.get(MessageBuilder)
builder2 = scope.get(MessageBuilder)
assert builder1 is not builder2
Best for:
- Stateless services.
- Services that need fresh state.
- Temporary resources.
Scope Required
Transient services must be resolved within a scope, even if they don't use scoped dependencies. This ensures proper cleanup of resources if the transient service itself or one of its dependencies needs to perform cleanup.
Lifetime Rules¶
- Singletons can depend only on other singletons.
- Scoped and transient services can depend on any lifetime.
- Parameters can be injected into all lifetimes.
Choosing a Lifetime
- Start with singleton unless you have a reason not to.
- Use scoped for request-specific state.
- Use transient for fresh instances or temporary resources.
Scoped services and decorated functions¶
Wireup lets you apply the container as a decorator. The provided integrations also decorate for you the routes/views where Wireup services are used.
For such cases, you don't need to do any scope management yourself and can simply ask for the scoped/transient services in the function's signature. The decorator can enter a scope and exit it once the function returns.