def __init__(self, conn=None, parent=None, protocol=None): Configurable.__init__(self) self._defaultconn = conn self._parent = parent self._lockconnmark = None if protocol: self._protocol = protocol else: if parent: self._protocol = parent._protocol else: self._protocol = Redis()
def __init__(self, conn = None, parent = None, protocol = None): Configurable.__init__(self) self._defaultconn = conn self._parent = parent self._lockconnmark = None if protocol: self._protocol = protocol else: if parent: self._protocol = parent._protocol else: self._protocol = Redis()
class RedisClientBase(Configurable): ''' Connect to Redis server ''' # Default connection URL for Redis client _default_url = 'tcp://localhost/' # Wait for the connection setup before raise an exception _default_timeout = 10 # Select database _default_db = 0 def __init__(self, conn=None, parent=None, protocol=None): Configurable.__init__(self) self._defaultconn = conn self._parent = parent self._lockconnmark = None if protocol: self._protocol = protocol else: if parent: self._protocol = parent._protocol else: self._protocol = Redis() def _get_connection(self, container, connection): if not connection.connected: for m in container.waitWithTimeout( self.timeout, self._protocol.statematcher( connection, RedisConnectionStateEvent.CONNECTION_UP, False)): yield m if container.timeout: raise RedisConnectionDown('Disconnected from redis server') def _get_default_connection(self, container): if not self._defaultconn: raise RedisConnectionDown('Not connected to redis server') if self._lockconnmark is not None: if self._lockconnmark >= 0: if not self._defaultconn.connected or self._defaultconn.connmark != self._lockconnmark: raise RedisConnectionRestarted( 'Disconnected from redis server; reconnected is not allowed in with scope' ) else: return for m in self._get_connection(container, self._defaultconn): yield m if self._lockconnmark is not None and self._lockconnmark < 0: self._lockconnmark = self._defaultconn.connmark def _shutdown_conn(self, container, connection): if connection: if connection.connected: # Send quit try: for m in self._protocol.send_command( connection, container, 'QUIT'): yield m for m in container.waitWithTimeout( 1, self._protocol.statematcher(connection)): yield m except Exception: for m in connection.shutdown(): yield m else: if container.timeout: for m in connection.shutdown(True): yield m else: for m in connection.shutdown(): yield m def shutdown(self, container): ''' Shutdown all connections to Redis server ''' c = self._defaultconn self._defaultconn = None for m in self._shutdown_conn(container, c): yield m def release(self, container): ''' Release the connection, leave it to be reused later. ''' if not self._parent: for m in self.shutdown(container): yield m else: for m in self._parent._release_conn(container, self._defaultconn): yield m @contextmanager def context(self, container, release=True, lockconn=True): ''' Use with statement to manage the connection :params release: if True(default), release the connection when leaving with scope :params lockconn: if True(default), do not allow reconnect during with scope; execute commands on a disconnected connection raises Exceptions. ''' try: if lockconn: if self._lockconnmark is None: # Lock next connmark self._lockconnmark = -1 locked = True yield self finally: if locked: self._lockconnmark = None self._lockconnmark = None if release: container.subroutine(self.release(container), False) @_conn def execute_command(self, container, *args): ''' execute command on current connection ''' for m in self._protocol.execute_command(self._defaultconn, container, *args): yield m @_conn def batch_execute(self, container, *cmds): ''' execute a batch of commands on current connection in pipeline mode ''' for m in self._protocol.batch_execute(self._defaultconn, container, *cmds): yield m def register_script(self, container, script): ''' register a script to this connection. :returns: registered script. This is a tuple (sha1, script). Pass the tuple to eval_registered, ensure_registerd as registerd_script parameter. ''' if len(script) < 43: container.retvalue = (None, script) else: for m in self.execute_command(container, 'SCRIPT', 'LOAD', script): yield m container.retvalue = (container.retvalue, script) def eval_registered(self, container, registerd_script, *args): ''' eval a registered script. If the script is not cached on the server, it is automatically cached. ''' if registerd_script[0]: try: for m in self.execute_command(container, 'EVALSHA', registerd_script[0], *args): yield m except RedisReplyException as exc: if exc.subtype == 'NOSCRIPT': for m in self.execute_command(container, 'EVAL', registerd_script[1], *args): yield m else: raise else: for m in self.execute_command(container, 'EVAL', registerd_script[1], *args): yield m def ensure_registerd(self, container, *scripts): ''' Ensure that these scripts are cached on the server. Important when using scripts with batch_execute. :param container: routine container. :param \*scripts: registered script tuples, return value of register_script ''' loading = dict((s[0], s[1]) for s in scripts if s[0]) if loading: keys = list(loading.keys()) for m in self.execute_command(container, 'SCRIPT', 'EXISTS', *keys): yield m r = container.retvalue cmds = [('SCRIPT', 'LOAD', s) for s in (loading[keys[i]] for i in range(0, len(keys)) if not r[i])] if cmds: for m in self.batch_execute(container, cmds): yield m
class RedisClientBase(Configurable): ''' Connect to Redis server ''' _default_url = 'tcp://localhost/' _default_timeout = 10 _default_db = 0 def __init__(self, conn = None, parent = None, protocol = None): Configurable.__init__(self) self._defaultconn = conn self._parent = parent self._lockconnmark = None if protocol: self._protocol = protocol else: if parent: self._protocol = parent._protocol else: self._protocol = Redis() def _get_connection(self, container, connection): if not connection.connected: for m in container.waitWithTimeout(self.timeout, self._protocol.statematcher(connection, RedisConnectionStateEvent.CONNECTION_UP, False)): yield m if container.timeout: raise RedisConnectionDown('Disconnected from redis server') def _get_default_connection(self, container): if not self._defaultconn: raise RedisConnectionDown('Not connected to redis server') if self._lockconnmark is not None: if self._lockconnmark >= 0: if not self._defaultconn.connected or self._defaultconn.connmark != self._lockconnmark: raise RedisConnectionRestarted('Disconnected from redis server; reconnected is not allowed in with scope') else: return for m in self._get_connection(container, self._defaultconn): yield m if self._lockconnmark is not None and self._lockconnmark < 0: self._lockconnmark = self._defaultconn.connmark def _shutdown_conn(self, container, connection): if connection: if connection.connected: # Send quit try: for m in self._protocol.send_command(connection, container, 'QUIT'): yield m for m in container.waitWithTimeout(1, self._protocol.statematcher(connection)): yield m except Exception: for m in connection.shutdown(): yield m else: if container.timeout: for m in connection.shutdown(True): yield m else: for m in connection.shutdown(): yield m def shutdown(self, container): ''' Shutdown all connections to Redis server ''' c = self._defaultconn self._defaultconn = None for m in self._shutdown_conn(container, c): yield m def release(self, container): ''' Release the connection, leave it to be reused later. ''' if not self._parent: for m in self.shutdown(container): yield m else: for m in self._parent._release_conn(container, self._defaultconn): yield m @contextmanager def context(self, container, release = True, lockconn = True): ''' Use with statement to manage the connection :params release: if True(default), release the connection when leaving with scope :params lockconn: if True(default), do not allow reconnect during with scope; execute commands on a disconnected connection raises Exceptions. ''' try: if lockconn: if self._lockconnmark is None: # Lock next connmark self._lockconnmark = -1 locked = True yield self finally: if locked: self._lockconnmark = None self._lockconnmark = None if release: container.subroutine(self.release(container), False) @_conn def execute_command(self, container, *args): ''' execute command on current connection ''' for m in self._protocol.execute_command(self._defaultconn, container, *args): yield m @_conn def batch_execute(self, container, *cmds): ''' execute a batch of commands on current connection in pipeline mode ''' for m in self._protocol.batch_execute(self._defaultconn, container, *cmds): yield m def register_script(self, container, script): ''' register a script to this connection. :returns: registered script. This is a tuple (sha1, script). Pass the tuple to eval_registered, ensure_registerd as registerd_script parameter. ''' if len(script) < 43: container.retvalue = (None, script) else: for m in self.execute_command(container, 'SCRIPT', 'LOAD', script): yield m container.retvalue = (container.retvalue, script) def eval_registered(self, container, registerd_script, *args): ''' eval a registered script. If the script is not cached on the server, it is automatically cached. ''' if registerd_script[0]: try: for m in self.execute_command(container, 'EVALSHA', registerd_script[0], *args): yield m except RedisReplyException as exc: if exc.subtype == 'NOSCRIPT': for m in self.execute_command(container, 'EVAL', registerd_script[1], *args): yield m else: raise else: for m in self.execute_command(container, 'EVAL', registerd_script[1], *args): yield m def ensure_registerd(self, container, *scripts): ''' Ensure that these scripts are cached on the server. Important when using scripts with batch_execute. :param container: routine container. :param *scripts: registered script tuples, return value of register_script ''' loading = dict((s[0], s[1]) for s in scripts if s[0]) if loading: keys = list(loading.keys()) for m in self.execute_command(container, 'SCRIPT', 'EXISTS', *keys): yield m r = container.retvalue cmds = [('SCRIPT', 'LOAD', s) for s in (loading[keys[i]] for i in range(0, len(keys)) if not r[i])] if cmds: for m in self.batch_execute(container, cmds): yield m