@@ -86,19 +86,24 @@ class PoolConnectionHolder:
86
86
87
87
__slots__ = ('_con' , '_pool' , '_loop' ,
88
88
'_connect_args' , '_connect_kwargs' ,
89
- '_max_queries' , '_setup' , '_init' )
89
+ '_max_queries' , '_setup' , '_init' ,
90
+ '_max_inactive_time' , '_in_use' ,
91
+ '_inactive_callback' )
90
92
91
93
def __init__ (self , pool , * , connect_args , connect_kwargs ,
92
- max_queries , setup , init ):
94
+ max_queries , setup , init , max_inactive_time ):
93
95
94
96
self ._pool = pool
95
97
self ._con = None
96
98
97
99
self ._connect_args = connect_args
98
100
self ._connect_kwargs = connect_kwargs
99
101
self ._max_queries = max_queries
102
+ self ._max_inactive_time = max_inactive_time
100
103
self ._setup = setup
101
104
self ._init = init
105
+ self ._inactive_callback = None
106
+ self ._in_use = False
102
107
103
108
async def connect (self ):
104
109
assert self ._con is None
@@ -134,6 +139,8 @@ async def acquire(self) -> PoolConnectionProxy:
134
139
if self ._con is None :
135
140
await self .connect ()
136
141
142
+ self ._maybe_cancel_inactive_callback ()
143
+
137
144
proxy = PoolConnectionProxy (self , self ._con )
138
145
139
146
if self ._setup is not None :
@@ -154,9 +161,13 @@ async def acquire(self) -> PoolConnectionProxy:
154
161
self ._con = None
155
162
raise ex
156
163
164
+ self ._in_use = True
157
165
return proxy
158
166
159
167
async def release (self ):
168
+ assert self ._in_use
169
+ self ._in_use = False
170
+
160
171
if self ._con .is_closed ():
161
172
self ._con = None
162
173
@@ -181,7 +192,13 @@ async def release(self):
181
192
self ._con = None
182
193
raise ex
183
194
195
+ assert self ._inactive_callback is None
196
+ if self ._max_inactive_time and self ._con is not None :
197
+ self ._inactive_callback = self ._pool ._loop .call_later (
198
+ self ._max_inactive_time , self ._deactivate_connection )
199
+
184
200
async def close (self ):
201
+ self ._maybe_cancel_inactive_callback ()
185
202
if self ._con is None :
186
203
return
187
204
if self ._con .is_closed ():
@@ -194,6 +211,7 @@ async def close(self):
194
211
self ._con = None
195
212
196
213
def terminate (self ):
214
+ self ._maybe_cancel_inactive_callback ()
197
215
if self ._con is None :
198
216
return
199
217
if self ._con .is_closed ():
@@ -205,6 +223,18 @@ def terminate(self):
205
223
finally :
206
224
self ._con = None
207
225
226
+ def _maybe_cancel_inactive_callback (self ):
227
+ if self ._inactive_callback is not None :
228
+ self ._inactive_callback .cancel ()
229
+ self ._inactive_callback = None
230
+
231
+ def _deactivate_connection (self ):
232
+ assert not self ._in_use
233
+ if self ._con is None or self ._con .is_closed ():
234
+ return
235
+ self ._con .terminate ()
236
+ self ._con = None
237
+
208
238
209
239
class Pool :
210
240
"""A connection pool.
@@ -225,6 +255,7 @@ def __init__(self, *connect_args,
225
255
min_size ,
226
256
max_size ,
227
257
max_queries ,
258
+ max_inactive_connection_lifetime ,
228
259
setup ,
229
260
init ,
230
261
loop ,
@@ -247,6 +278,11 @@ def __init__(self, *connect_args,
247
278
if max_queries <= 0 :
248
279
raise ValueError ('max_queries is expected to be greater than zero' )
249
280
281
+ if max_inactive_connection_lifetime < 0 :
282
+ raise ValueError (
283
+ 'max_inactive_connection_lifetime is expected to be greater '
284
+ 'or equal to zero' )
285
+
250
286
self ._minsize = min_size
251
287
self ._maxsize = max_size
252
288
@@ -265,6 +301,7 @@ def __init__(self, *connect_args,
265
301
connect_args = connect_args ,
266
302
connect_kwargs = connect_kwargs ,
267
303
max_queries = max_queries ,
304
+ max_inactive_time = max_inactive_connection_lifetime ,
268
305
setup = setup ,
269
306
init = init )
270
307
@@ -511,6 +548,7 @@ def create_pool(dsn=None, *,
511
548
min_size = 10 ,
512
549
max_size = 10 ,
513
550
max_queries = 50000 ,
551
+ max_inactive_connection_lifetime = 300.0 ,
514
552
setup = None ,
515
553
init = None ,
516
554
loop = None ,
@@ -548,6 +586,9 @@ def create_pool(dsn=None, *,
548
586
:param int max_size: Max number of connections in the pool.
549
587
:param int max_queries: Number of queries after a connection is closed
550
588
and replaced with a new connection.
589
+ :param float max_inactive_connection_lifetime:
590
+ Number of seconds after which inactive connections in the
591
+ pool will be closed. Pass ``0`` to disable this mechanism.
551
592
:param coroutine setup: A coroutine to prepare a connection right before
552
593
it is returned from :meth:`~pool.Pool.acquire`.
553
594
An example use case would be to automatically
@@ -567,7 +608,9 @@ def create_pool(dsn=None, *,
567
608
An :exc:`~asyncpg.exceptions.InterfaceError` will be raised on any
568
609
attempted operation on a released connection.
569
610
"""
570
- return Pool (dsn ,
571
- min_size = min_size , max_size = max_size ,
572
- max_queries = max_queries , loop = loop , setup = setup , init = init ,
573
- ** connect_kwargs )
611
+ return Pool (
612
+ dsn ,
613
+ min_size = min_size , max_size = max_size ,
614
+ max_queries = max_queries , loop = loop , setup = setup , init = init ,
615
+ max_inactive_connection_lifetime = max_inactive_connection_lifetime ,
616
+ ** connect_kwargs )
0 commit comments