Skip to content

Commit

Permalink
Merge pull request #11 from thefab/autoconnect
Browse files Browse the repository at this point in the history
Autoconnect feature
  • Loading branch information
thefab committed May 9, 2015
2 parents d63c2de + b44bfaf commit 7265468
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- coroutine friendly
- production ready (timeouts, connection pool, error management)
- nearly all redis features (pipeline, pubsub, standard commands)
- autoconnection, autoreconnection

## Full documentation

Expand Down
24 changes: 23 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import tornado.testing
import tornado.ioloop
import tornado
import toro
import functools

from tornadis.client import Client
from tornadis.exceptions import ClientError, ConnectionError
from tornadis.exceptions import ConnectionError
from support import test_redis_or_raise_skiptest


Expand All @@ -33,6 +35,26 @@ def test_ping(self):
self.assertEquals(res, b"PONG")
yield c.disconnect()

@tornado.testing.gen_test
def test_autoconnect_future(self):
c = Client(autoconnect=True)
res = yield c.call('PING')
self.assertEquals(res, b"PONG")
yield c.disconnect()

def _test_autoconnect_callback_cb(self, condition, result):
self.assertEquals(result, b"PONG")
condition.notify()

@tornado.testing.gen_test
def test_autoconnect_callback(self):
condition = toro.Condition()
c = Client(autoconnect=True)
cb = functools.partial(self._test_autoconnect_callback_cb, condition)
c.async_call('PING', callback=cb)
yield condition.wait()
yield c.disconnect()

@tornado.testing.gen_test
def test_discard(self):
c = Client()
Expand Down
37 changes: 33 additions & 4 deletions tornadis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class Client(object):
write_page_size (int): page size for writing.
connect_timeout (int): timeout (in seconds) for connecting.
subscribed (boolean): True if the client is in subscription mode.
autoconnect (boolean): True if the client is in autoconnect mode
(and in autoreconnection mode) (default False)
return_connection_error (boolean): if True, return a ConnectionError
object if the redis server close the connection. If False, return
None (default) in that particular case.
Expand All @@ -45,6 +47,7 @@ def __init__(self, host=tornadis.DEFAULT_HOST, port=tornadis.DEFAULT_PORT,
read_page_size=tornadis.DEFAULT_READ_PAGE_SIZE,
write_page_size=tornadis.DEFAULT_WRITE_PAGE_SIZE,
connect_timeout=tornadis.DEFAULT_CONNECT_TIMEOUT,
autoconnect=False,
return_connection_error=False,
ioloop=None):
"""Constructor.
Expand All @@ -55,6 +58,8 @@ def __init__(self, host=tornadis.DEFAULT_HOST, port=tornadis.DEFAULT_PORT,
read_page_size (int): page size for reading.
write_page_size (int): page size for writing.
connect_timeout (int): timeout (in seconds) for connecting.
autoconnect (boolean): True if the client is in autoconnect mode
(and in autoreconnection mode) (default False)
return_connection_error (boolean): if True, return a
ConnectionError object if the redis server close the
connection. If False, return None (default) in that particular
Expand All @@ -67,6 +72,7 @@ def __init__(self, host=tornadis.DEFAULT_HOST, port=tornadis.DEFAULT_PORT,
self.write_page_size = write_page_size
self.connect_timeout = connect_timeout
self.return_connection_error = return_connection_error
self.autoconnect = autoconnect
self.__ioloop = ioloop or tornado.ioloop.IOLoop.instance()
self.__connection = None
self.subscribed = False
Expand Down Expand Up @@ -190,9 +196,22 @@ def foobar():
result = yield client.call("HSET", "key", "field", "val")
"""
if not self.is_connected():
raise ClientError("you are not connected")
if self.autoconnect:
# We use this method only when we are not contected
# to void performance penaly due to gen.coroutine decorator
return self._call_with_autoconnect(*args)
else:
raise ClientError("you are not connected")
return self._call(*args)

@tornado.gen.coroutine
def _call_with_autoconnect(self, *args):
yield self.connect()
if not self.is_connected():
raise ClientError("Impossible to autoconnect")
res = yield self._call(*args)
raise tornado.gen.Return(res)

def async_call(self, *args, **kwargs):
"""Calls a redis command, waits for the reply and call a callback.
Expand All @@ -217,11 +236,21 @@ def async_call(self, *args, **kwargs):
pass
>>> client.async_call("HSET", "key", "field", "val", callback=cb)
"""
if not self.is_connected():
raise ClientError("you are not connected")
def after_autoconnect_callback(future):
if self.is_connected():
self._call(*args, **kwargs)

if 'callback' not in kwargs:
kwargs['callback'] = discard_reply_cb
return self._call(*args, **kwargs)
if not self.is_connected():
if self.autoconnect:
connect_future = self.connect()
self.__ioloop.add_future(connect_future,
after_autoconnect_callback)
else:
raise ClientError("you are not connected")
else:
self._call(*args, **kwargs)

def _call(self, *args, **kwargs):
callback = False
Expand Down

0 comments on commit 7265468

Please sign in to comment.