def get_toredis_client(): redis_client = Client(host=settings.redis_host, port=settings.redis_port, selected_db=settings.redis_db, password=settings.redis_password) redis_client.connect() return redis_client
class MessageHandler(WebSocketHandler): def __init__(self, *args, **kwargs): super(MessageHandler, self).__init__(*args, **kwargs) self.redis = Client() self.redis.connect() def get_current_user(self): user = self.get_secure_cookie("user") if user is None: return '' else: return user.strip('" ') def on_message(self, msg): msginfo = loads(msg) #listens for handshake from page if "user:" in msginfo['msg']: self.channel = msginfo['msg'].split(':')[1] #need to split the rest off to new func so it can be asynchronous self.listen() # Decorator turns the function into an asynchronous generator object @tornado.gen.engine def listen(self): #runs task given, with the yield required to get returned value #equivalent of callback/wait pairing from tornado.gen yield tornado.gen.Task(self.redis.subscribe, self.channel) if not self.redis.subscribed: self.write_message('ERROR IN SUBSCRIPTION') #listen from tornadoredis makes the listen object asynchronous #if using standard redis lib, it blocks while listening self.redis.listen(self.callback) # Try and fight race condition by loading from redis after listen # started need to use std redis lib because tornadoredis is in # subscribed state oldmessages = r_server.lrange(self.channel + ':messages', 0, -1) if oldmessages is not None: for message in oldmessages: self.write_message(message) def callback(self, msg): if msg.kind == 'message': self.write_message(str(msg.body)) @tornado.gen.engine def on_close(self): yield tornado.gen.Task(self.redis.unsubscribe, self.channel) self.redis.disconnect()
class MessageHandler(WebSocketHandler): def __init__(self, *args, **kwargs): super(MessageHandler, self).__init__(*args, **kwargs) self.redis = Client() self.redis.connect() def get_current_user(self): user = self.get_secure_cookie("user") if user == None: return '' else: return user.strip('" ') def on_message(self, msg): msginfo = loads(msg) #listens for handshake from page if "user:" in msginfo['msg']: self.channel = msginfo['msg'].split(':')[1] #need to split the rest off to new func so it can be asynchronous self.listen() #decorator turns the function into an asynchronous generator object @tornado.gen.engine def listen(self): #runs task given, with the yield required to get returned value #equivalent of callback/wait pairing from tornado.gen yield tornado.gen.Task(self.redis.subscribe, self.channel) if not self.redis.subscribed: self.write_message('ERROR IN SUBSCRIPTION') #listen from tornadoredis makes the listen object asynchronous #if using standard redis lib, it blocks while listening self.redis.listen(self.callback) #try and fight race condition by loading from redis after listen started #need to use std redis lib because tornadoredis is in subscribed state oldmessages = r_server.lrange(self.channel + ':messages', 0, -1) if oldmessages != None: for message in oldmessages: self.write_message(message) def callback(self, msg): if msg.kind == 'message': self.write_message(str(msg.body)) @tornado.gen.engine def on_close(self): yield tornado.gen.Task(self.redis.unsubscribe, self.channel) self.redis.disconnect()
class RedisSubscriber: _instance = None _lock = Lock() def __init__(self): worker_logger.info('Initialized Redis Subscriber instance') self._client = Client(host=REDIS_HOST, port=int(REDIS_PORT)) self._subscribers = {} self._listen() def __del__(self): worker_logger.info('Redis Subscriber was successfully destroyed') @classmethod def instance(cls): with cls._lock: if cls._instance is None: cls._instance = RedisSubscriber() return cls._instance def subscribe(self, channel_key, callback): worker_logger.info( 'Subscribing channel - %s , with the callback - %s' % (channel_key, callback.__name__)) self._subscribers.update({channel_key: callback}) def unsubscribe(self, channel_key): worker_logger.info("Unsubscribing from channel - %s" % channel_key) if channel_key in self._subscribers: del self._subscribers[channel_key] @tornado.gen.engine def _listen(self): self._client.connect() yield tornado.gen.Task( self._client.psubscribe, "__keyspace*:%s" % (REDIS_GENERAL_CHANNEL % '*')) self._client.listen(self._message_handler) def _message_handler(self, message): if message.kind == 'pmessage': channel_key = re.search(REDIS_GENERAL_CHANNEL % '(.*)', message.channel) channel_callbacks = [] if channel_key is not None: channel_key = channel_key.group(0) if channel_key in self._subscribers: channel_callbacks[0] = self._subscribers.get(channel_key) else: for subscriber_channel_key in self._subscribers.keys(): re_channel_key = subscriber_channel_key.replace( '*', '.*') if re.match(re_channel_key, channel_key): channel_callbacks.append( self._subscribers.get(subscriber_channel_key)) if len(channel_callbacks): for channel_callback in channel_callbacks: try: tornado.ioloop.IOLoop.instance().call_later( callback=channel_callback, delay=0, message=message) except Exception as e: worker_logger.warn('Failed to run channel callback') worker_logger.exception(e)