Skip to content

Commit 4dec96f

Browse files
kmerenkovandymccurdy
authored andcommitted
[issue 29] Redis instance doesn't use shared connection pool by default
* Redis constructor accepts connection_pool keyword argument, that defaults to None (no shared connection pool). However, you can create ConnectionManager instance yourself and pass it to as many Redis instances as you want, making them use shared connection pool. * Renamed ConnectionManager to ConnectionPool. * Exported ConnectionPool, so now you can import it in your code and create instances. * Removed test_pipeline_with_fresh_connection test, since all redis instances don't use shared pool by default now. * corrected few typos in comments. * repaired the rest of tests.
1 parent 4efa5de commit 4dec96f

File tree

4 files changed

+25
-33
lines changed

4 files changed

+25
-33
lines changed

redis/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# legacy imports
2-
from redis.client import Redis, connection_manager
2+
from redis.client import Redis, ConnectionPool
33
from redis.exceptions import RedisError, ConnectionError, AuthenticationError
44
from redis.exceptions import ResponseError, InvalidResponse, InvalidData
55

66
__all__ = [
7-
'Redis', 'connection_manager',
7+
'Redis', 'ConnectionPool',
88
'RedisError', 'ConnectionError', 'ResponseError', 'AuthenticationError'
99
'InvalidResponse', 'InvalidData',
1010
]

redis/client.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from redis.exceptions import RedisError, AuthenticationError
99

1010

11-
class ConnectionManager(threading.local):
11+
class ConnectionPool(threading.local):
1212
"Manages a list of connections on the local thread"
1313
def __init__(self):
1414
self.connections = {}
@@ -30,9 +30,6 @@ def get_all_connections(self):
3030
return self.connections.values()
3131

3232

33-
connection_manager = ConnectionManager()
34-
35-
3633
class Connection(object):
3734
"Manages TCP communication to and from a Redis server"
3835
def __init__(self, host='localhost', port=6379, db=0, password=None,
@@ -236,11 +233,13 @@ class Redis(threading.local):
236233

237234
def __init__(self, host='localhost', port=6379,
238235
db=0, password=None, socket_timeout=None,
236+
connection_pool=None,
239237
charset='utf-8', errors='strict'):
240238
self.encoding = charset
241239
self.errors = errors
242240
self.connection = None
243241
self.subscribed = False
242+
self.connection_pool = connection_pool and connection_pool or ConnectionPool()
244243
self.select(db, host, port, password, socket_timeout)
245244

246245
#### Legacty accessors of connection information ####
@@ -376,7 +375,7 @@ def encode(self, value):
376375
#### CONNECTION HANDLING ####
377376
def get_connection(self, host, port, db, password, socket_timeout):
378377
"Returns a connection object"
379-
conn = connection_manager.get_connection(
378+
conn = self.connection_pool.get_connection(
380379
host, port, db, password, socket_timeout)
381380
# if for whatever reason the connection gets a bad password, make
382381
# sure a subsequent attempt with the right password makes its way

tests/connection_pool.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,49 @@
55

66
class ConnectionPoolTestCase(unittest.TestCase):
77
def test_multiple_connections(self):
8-
# 2 clients to the same host/port/db should use the same connection
9-
r1 = redis.Redis(host='localhost', port=6379, db=9)
10-
r2 = redis.Redis(host='localhost', port=6379, db=9)
8+
# 2 clients to the same host/port/db/pool should use the same connection
9+
pool = redis.ConnectionPool()
10+
r1 = redis.Redis(host='localhost', port=6379, db=9, connection_pool=pool)
11+
r2 = redis.Redis(host='localhost', port=6379, db=9, connection_pool=pool)
1112
self.assertEquals(r1.connection, r2.connection)
12-
13-
# if one o them switches, they should have
13+
14+
# if one of them switches, they should have
1415
# separate conncetion objects
1516
r2.select(db=10, host='localhost', port=6379)
1617
self.assertNotEqual(r1.connection, r2.connection)
17-
18+
1819
conns = [r1.connection, r2.connection]
1920
conns.sort()
20-
21+
2122
# but returning to the original state shares the object again
2223
r2.select(db=9, host='localhost', port=6379)
2324
self.assertEquals(r1.connection, r2.connection)
24-
25+
2526
# the connection manager should still have just 2 connections
26-
mgr_conns = redis.connection_manager.get_all_connections()
27+
mgr_conns = pool.get_all_connections()
2728
mgr_conns.sort()
2829
self.assertEquals(conns, mgr_conns)
29-
30+
3031
def test_threaded_workers(self):
3132
r = redis.Redis(host='localhost', port=6379, db=9)
3233
r.set('a', 'foo')
3334
r.set('b', 'bar')
34-
35+
3536
def _info_worker():
3637
for i in range(50):
3738
_ = r.info()
3839
time.sleep(0.01)
39-
40+
4041
def _keys_worker():
4142
for i in range(50):
4243
_ = r.keys()
4344
time.sleep(0.01)
44-
45+
4546
t1 = threading.Thread(target=_info_worker)
4647
t2 = threading.Thread(target=_keys_worker)
4748
t1.start()
4849
t2.start()
49-
50+
5051
for i in [t1, t2]:
5152
i.join()
52-
53-
53+

tests/pipeline.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,13 @@ def test_pipeline(self):
2424
]
2525
)
2626

27-
def test_pipeline_with_fresh_connection(self):
28-
redis.client.connection_manager.connections.clear()
29-
self.client = redis.Redis(host='localhost', port=6379, db=9)
30-
pipe = self.client.pipeline()
31-
pipe.set('a', 'b')
32-
self.assertEquals(pipe.execute(), [True])
33-
3427
def test_invalid_command_in_pipeline(self):
3528
# all commands but the invalid one should be excuted correctly
3629
self.client['c'] = 'a'
3730
pipe = self.client.pipeline()
3831
pipe.set('a', 1).set('b', 2).lpush('c', 3).set('d', 4)
3932
result = pipe.execute()
40-
33+
4134
self.assertEquals(result[0], True)
4235
self.assertEquals(self.client['a'], '1')
4336
self.assertEquals(result[1], True)
@@ -48,11 +41,11 @@ def test_invalid_command_in_pipeline(self):
4841
self.assertEquals(self.client['c'], 'a')
4942
self.assertEquals(result[3], True)
5043
self.assertEquals(self.client['d'], '4')
51-
44+
5245
# make sure the pipe was restored to a working state
5346
self.assertEquals(pipe.set('z', 'zzz').execute(), [True])
5447
self.assertEquals(self.client['z'], 'zzz')
55-
48+
5649
def test_pipeline_cannot_select(self):
5750
pipe = self.client.pipeline()
5851
self.assertRaises(redis.RedisError,

0 commit comments

Comments
 (0)