0
# Resource Management
1
2
Resource management provides base classes and providers for handling resource lifecycles with automatic initialization and cleanup. Resources represent objects that require explicit setup and teardown, such as database connections, file handles, or network connections.
3
4
## Capabilities
5
6
### Base Resource Classes
7
8
Abstract base classes that define the resource interface for synchronous and asynchronous resources.
9
10
```python { .api }
11
class Resource:
12
"""Abstract synchronous resource with initialization and cleanup."""
13
def __init__(self, *args, **kwargs): ...
14
15
def init(self, *args, **kwargs):
16
"""
17
Initialize the resource.
18
19
Parameters:
20
- *args: Positional arguments for initialization
21
- **kwargs: Keyword arguments for initialization
22
23
Returns:
24
The initialized resource object
25
"""
26
27
def shutdown(self, resource):
28
"""
29
Shutdown and cleanup the resource.
30
31
Parameters:
32
- resource: The resource object to cleanup
33
"""
34
35
def __enter__(self):
36
"""Context manager entry."""
37
38
def __exit__(self, *exc_info):
39
"""Context manager exit with cleanup."""
40
41
class AsyncResource:
42
"""Abstract asynchronous resource with async initialization and cleanup."""
43
def __init__(self, *args, **kwargs): ...
44
45
async def init(self, *args, **kwargs):
46
"""
47
Asynchronously initialize the resource.
48
49
Parameters:
50
- *args: Positional arguments for initialization
51
- **kwargs: Keyword arguments for initialization
52
53
Returns:
54
The initialized resource object
55
"""
56
57
async def shutdown(self, resource):
58
"""
59
Asynchronously shutdown and cleanup the resource.
60
61
Parameters:
62
- resource: The resource object to cleanup
63
"""
64
65
async def __aenter__(self):
66
"""Async context manager entry."""
67
68
async def __aexit__(self, *exc_info):
69
"""Async context manager exit with cleanup."""
70
```
71
72
### Synchronous Resource Implementation
73
74
Implementation pattern for synchronous resources that require initialization and cleanup.
75
76
Usage example:
77
78
```python
79
from dependency_injector.resources import Resource
80
81
class DatabaseResource(Resource):
82
def init(self, connection_string, pool_size=10):
83
"""Initialize database connection pool."""
84
print(f"Connecting to database: {connection_string}")
85
connection_pool = create_connection_pool(
86
connection_string,
87
pool_size=pool_size
88
)
89
print(f"Created connection pool with {pool_size} connections")
90
return connection_pool
91
92
def shutdown(self, connection_pool):
93
"""Close all database connections."""
94
print("Closing database connection pool")
95
connection_pool.close_all()
96
print("Database connections closed")
97
98
# Usage with provider
99
from dependency_injector import providers
100
101
database = providers.Resource(
102
DatabaseResource,
103
connection_string="postgresql://localhost/mydb",
104
pool_size=20
105
)
106
107
# Initialize resource
108
db_pool = database() # Calls init() method
109
# Use database pool
110
result = db_pool.execute("SELECT * FROM users")
111
# Cleanup is handled automatically or manually
112
database.shutdown() # Calls shutdown() method
113
```
114
115
### Asynchronous Resource Implementation
116
117
Implementation pattern for asynchronous resources with async/await support.
118
119
Usage example:
120
121
```python
122
from dependency_injector.resources import AsyncResource
123
import asyncio
124
import aioredis
125
126
class RedisResource(AsyncResource):
127
async def init(self, host="localhost", port=6379, db=0):
128
"""Initialize async Redis connection."""
129
print(f"Connecting to Redis: {host}:{port}/{db}")
130
redis_client = await aioredis.from_url(
131
f"redis://{host}:{port}/{db}"
132
)
133
print("Redis connection established")
134
return redis_client
135
136
async def shutdown(self, redis_client):
137
"""Close Redis connection."""
138
print("Closing Redis connection")
139
await redis_client.close()
140
print("Redis connection closed")
141
142
# Usage with provider
143
redis = providers.Resource(
144
RedisResource,
145
host="localhost",
146
port=6379,
147
db=0
148
)
149
150
# Async usage
151
async def main():
152
redis_client = await redis() # Calls init() method
153
await redis_client.set("key", "value")
154
value = await redis_client.get("key")
155
print(f"Retrieved value: {value}")
156
await redis.shutdown() # Calls shutdown() method
157
158
asyncio.run(main())
159
```
160
161
### File Resource Implementation
162
163
Example of file resource management with proper cleanup.
164
165
```python
166
from dependency_injector.resources import Resource
167
168
class FileResource(Resource):
169
def init(self, filepath, mode="r", encoding="utf-8"):
170
"""Open file handle."""
171
print(f"Opening file: {filepath} (mode: {mode})")
172
file_handle = open(filepath, mode, encoding=encoding)
173
return file_handle
174
175
def shutdown(self, file_handle):
176
"""Close file handle."""
177
print(f"Closing file: {file_handle.name}")
178
file_handle.close()
179
180
# Usage
181
config_file = providers.Resource(
182
FileResource,
183
filepath="config.json",
184
mode="r"
185
)
186
187
# Use as context manager
188
with config_file() as f:
189
config_data = f.read()
190
# File is automatically closed
191
```
192
193
### HTTP Client Resource Implementation
194
195
Example of HTTP client resource with connection pooling.
196
197
```python
198
from dependency_injector.resources import AsyncResource
199
import aiohttp
200
201
class HttpClientResource(AsyncResource):
202
async def init(self, base_url, timeout=30, connector_limit=100):
203
"""Initialize HTTP client session."""
204
print(f"Creating HTTP client for: {base_url}")
205
timeout_config = aiohttp.ClientTimeout(total=timeout)
206
connector = aiohttp.TCPConnector(limit=connector_limit)
207
208
session = aiohttp.ClientSession(
209
base_url=base_url,
210
timeout=timeout_config,
211
connector=connector
212
)
213
print("HTTP client session created")
214
return session
215
216
async def shutdown(self, session):
217
"""Close HTTP client session."""
218
print("Closing HTTP client session")
219
await session.close()
220
print("HTTP client session closed")
221
222
# Usage
223
api_client = providers.Resource(
224
HttpClientResource,
225
base_url="https://api.example.com",
226
timeout=60
227
)
228
229
async def make_request():
230
client = await api_client()
231
async with client.get("/users") as response:
232
data = await response.json()
233
return data
234
```
235
236
### Resource Provider Integration
237
238
Resources integrate with the dependency injection system through resource providers.
239
240
```python
241
from dependency_injector import containers, providers
242
from dependency_injector.resources import Resource
243
244
class DatabaseResource(Resource):
245
def init(self, connection_string):
246
return create_database_connection(connection_string)
247
248
def shutdown(self, connection):
249
connection.close()
250
251
class Container(containers.DeclarativeContainer):
252
config = providers.Configuration()
253
254
# Resource provider
255
database = providers.Resource(
256
DatabaseResource,
257
connection_string=config.database.url
258
)
259
260
# Other providers can use the resource
261
user_repository = providers.Factory(
262
UserRepository,
263
database=database # Automatically initialized resource
264
)
265
266
# Container automatically manages resource lifecycle
267
container = Container()
268
container.config.from_dict({
269
"database": {"url": "postgresql://localhost/mydb"}
270
})
271
272
# Initialize all resources
273
await container.init_resources()
274
275
# Use services that depend on resources
276
user_repo = container.user_repository()
277
users = user_repo.get_all_users()
278
279
# Shutdown all resources
280
await container.shutdown_resources()
281
```
282
283
### Resource Context Managers
284
285
Resources support context manager protocols for automatic cleanup.
286
287
```python
288
# Synchronous context manager
289
class DatabaseResource(Resource):
290
def init(self, connection_string):
291
return create_connection(connection_string)
292
293
def shutdown(self, connection):
294
connection.close()
295
296
# Usage as context manager
297
database = providers.Resource(DatabaseResource, "postgresql://localhost/db")
298
299
with database() as db_connection:
300
# Use database connection
301
result = db_connection.execute("SELECT * FROM users")
302
# Connection is automatically closed
303
304
# Asynchronous context manager
305
class AsyncDatabaseResource(AsyncResource):
306
async def init(self, connection_string):
307
return await create_async_connection(connection_string)
308
309
async def shutdown(self, connection):
310
await connection.close()
311
312
# Usage as async context manager
313
async_database = providers.Resource(AsyncDatabaseResource, "postgresql://localhost/db")
314
315
async with async_database() as db_connection:
316
# Use async database connection
317
result = await db_connection.execute("SELECT * FROM users")
318
# Connection is automatically closed
319
```
320
321
### Resource Dependency Injection
322
323
Resources can be injected into functions and methods using dependency wiring.
324
325
```python
326
from dependency_injector.wiring import inject, Provide, Closing
327
328
@inject
329
def process_users(
330
database = Provide[Container.database],
331
cache = Provide[Container.redis],
332
# Resource cleanup markers
333
db_cleanup = Closing[Container.database],
334
cache_cleanup = Closing[Container.redis]
335
):
336
# Use resources
337
users = database.query("SELECT * FROM users")
338
cache.set("users", users)
339
340
# Resources will be automatically cleaned up
341
return users
342
343
# Wire container
344
container.wire(modules=[__name__])
345
```
346
347
### Resource Error Handling
348
349
Proper error handling in resource initialization and cleanup.
350
351
```python
352
from dependency_injector.resources import Resource
353
354
class RobustDatabaseResource(Resource):
355
def init(self, connection_string, max_retries=3):
356
"""Initialize with retry logic."""
357
for attempt in range(max_retries):
358
try:
359
print(f"Database connection attempt {attempt + 1}")
360
connection = create_connection(connection_string)
361
print("Database connection successful")
362
return connection
363
except ConnectionError as e:
364
print(f"Connection failed: {e}")
365
if attempt == max_retries - 1:
366
raise
367
time.sleep(2 ** attempt) # Exponential backoff
368
369
def shutdown(self, connection):
370
"""Shutdown with error handling."""
371
try:
372
if connection and not connection.is_closed():
373
connection.close()
374
print("Database connection closed")
375
except Exception as e:
376
print(f"Error closing database connection: {e}")
377
# Log error but don't raise to avoid masking original exceptions
378
```
379
380
### Resource Composition
381
382
Combining multiple resources into composite resources.
383
384
```python
385
class CompositeResource(Resource):
386
def init(self, db_config, redis_config):
387
"""Initialize multiple resources."""
388
database = DatabaseResource().init(**db_config)
389
redis = RedisResource().init(**redis_config)
390
391
return {
392
"database": database,
393
"redis": redis
394
}
395
396
def shutdown(self, resources):
397
"""Shutdown all resources."""
398
if "database" in resources:
399
DatabaseResource().shutdown(resources["database"])
400
if "redis" in resources:
401
RedisResource().shutdown(resources["redis"])
402
403
# Usage
404
composite = providers.Resource(
405
CompositeResource,
406
db_config={"connection_string": "postgresql://localhost/db"},
407
redis_config={"host": "localhost", "port": 6379}
408
)
409
```