Skip to content

Commit f05419e

Browse files
authored
Merge pull request #216 from aio-libs/pool-recylce
Pool recylce
2 parents 4b75b3f + f24fc7f commit f05419e

File tree

4 files changed

+48
-10
lines changed

4 files changed

+48
-10
lines changed

aiomysql/connection.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def __init__(self, host="localhost", user=None, password="",
163163
self._db = db
164164
self._no_delay = no_delay
165165
self._echo = echo
166+
self._last_usage = self._loop.time()
166167

167168
self._unix_socket = unix_socket
168169
if charset:
@@ -240,6 +241,11 @@ def echo(self):
240241
"""Return echo mode status."""
241242
return self._echo
242243

244+
@property
245+
def last_usage(self):
246+
"""Return time() when connection was used."""
247+
return self._last_usage
248+
243249
@property
244250
def loop(self):
245251
return self._loop
@@ -375,6 +381,7 @@ def cursor(self, cursor=None):
375381
:raises TypeError: cursor_class is not a subclass of Cursor.
376382
"""
377383
self._ensure_alive()
384+
self._last_usage = self._loop.time()
378385
if cursor is not None and not issubclass(cursor, Cursor):
379386
raise TypeError('Custom cursor must be subclass of Cursor')
380387

aiomysql/pool.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,21 @@
1010
_PoolAcquireContextManager, create_future, create_task)
1111

1212

13-
def create_pool(minsize=1, maxsize=10, echo=False, loop=None, **kwargs):
13+
def create_pool(minsize=1, maxsize=10, echo=False, pool_recycle=-1,
14+
loop=None, **kwargs):
1415
coro = _create_pool(minsize=minsize, maxsize=maxsize, echo=echo,
15-
loop=loop, **kwargs)
16+
pool_recycle=pool_recycle, loop=loop, **kwargs)
1617
return _PoolContextManager(coro)
1718

1819

1920
@asyncio.coroutine
20-
def _create_pool(minsize=1, maxsize=10, echo=False, loop=None, **kwargs):
21+
def _create_pool(minsize=1, maxsize=10, echo=False, pool_recycle=-1,
22+
loop=None, **kwargs):
2123
if loop is None:
2224
loop = asyncio.get_event_loop()
2325

24-
pool = Pool(minsize=minsize, maxsize=maxsize, echo=echo, loop=loop,
25-
**kwargs)
26+
pool = Pool(minsize=minsize, maxsize=maxsize, echo=echo,
27+
pool_recycle=pool_recycle, loop=loop, **kwargs)
2628
if minsize > 0:
2729
with (yield from pool._cond):
2830
yield from pool._fill_free_pool(False)
@@ -32,7 +34,7 @@ def _create_pool(minsize=1, maxsize=10, echo=False, loop=None, **kwargs):
3234
class Pool(asyncio.AbstractServer):
3335
"""Connection pool"""
3436

35-
def __init__(self, minsize, maxsize, echo, loop, **kwargs):
37+
def __init__(self, minsize, maxsize, echo, pool_recycle, loop, **kwargs):
3638
if minsize < 0:
3739
raise ValueError("minsize should be zero or greater")
3840
if maxsize < minsize:
@@ -48,6 +50,7 @@ def __init__(self, minsize, maxsize, echo, loop, **kwargs):
4850
self._closing = False
4951
self._closed = False
5052
self._echo = echo
53+
self._recycle = pool_recycle
5154

5255
@property
5356
def echo(self):
@@ -153,6 +156,12 @@ def _fill_free_pool(self, override_min):
153156
if conn._reader.at_eof():
154157
self._free.pop()
155158
conn.close()
159+
160+
elif (self._recycle > -1 and
161+
self._loop.time() - conn.last_usage > self._recycle):
162+
self._free.pop()
163+
conn.close()
164+
156165
else:
157166
self._free.rotate()
158167
n += 1

aiomysql/sa/engine.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,27 @@
1919

2020

2121
def create_engine(minsize=1, maxsize=10, loop=None,
22-
dialect=_dialect, **kwargs):
22+
dialect=_dialect, pool_recycle=-1, **kwargs):
2323
"""A coroutine for Engine creation.
2424
2525
Returns Engine instance with embedded connection pool.
2626
2727
The pool has *minsize* opened connections to PostgreSQL server.
2828
"""
2929
coro = _create_engine(minsize=minsize, maxsize=maxsize, loop=loop,
30-
dialect=dialect, **kwargs)
30+
dialect=dialect, pool_recycle=pool_recycle, **kwargs)
3131
return _EngineContextManager(coro)
3232

3333

3434
@asyncio.coroutine
3535
def _create_engine(minsize=1, maxsize=10, loop=None,
36-
dialect=_dialect, **kwargs):
36+
dialect=_dialect, pool_recycle=-1, **kwargs):
3737

3838
if loop is None:
3939
loop = asyncio.get_event_loop()
4040
pool = yield from aiomysql.create_pool(minsize=minsize, maxsize=maxsize,
41-
loop=loop, **kwargs)
41+
loop=loop,
42+
pool_recycle=pool_recycle, **kwargs)
4243
conn = yield from pool.acquire()
4344
try:
4445
return Engine(dialect, pool, **kwargs)

tests/test_pool.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,3 +497,24 @@ def test_cancelled_connection(pool_creator, loop):
497497
res = yield from cur2.fetchall()
498498
# If we receive [(1, 0)] - we retrieved old cursor's values
499499
assert list(res) == [(2, 0)]
500+
501+
502+
@asyncio.coroutine
503+
def test_pool_with_connection_recycling(pool_creator, loop):
504+
pool = yield from pool_creator(minsize=1,
505+
maxsize=1,
506+
pool_recycle=3)
507+
with (yield from pool) as conn:
508+
cur = yield from conn.cursor()
509+
yield from cur.execute('SELECT 1;')
510+
val = yield from cur.fetchone()
511+
assert (1,) == val
512+
513+
yield from asyncio.sleep(5, loop=loop)
514+
515+
assert 1 == pool.freesize
516+
with (yield from pool) as conn:
517+
cur = yield from conn.cursor()
518+
yield from cur.execute('SELECT 1;')
519+
val = yield from cur.fetchone()
520+
assert (1,) == val

0 commit comments

Comments
 (0)