2011-12-11 15 views
8

Sto usando Redis insieme con la mia applicazione Tornado con ASYC cliente Brukva, quando ho guardato le applicazioni di esempio al sito Brukva stanno facendo nuova connessione su "init" metodo websocketQual è il modo corretto di gestire la connessione Redis in Tornado? (Async - Pub/Sub)

class MessagesCatcher(tornado.websocket.WebSocketHandler): 
    def __init__(self, *args, **kwargs): 
     super(MessagesCatcher, self).__init__(*args, **kwargs) 
     self.client = brukva.Client() 
     self.client.connect() 
     self.client.subscribe('test_channel') 

    def open(self): 
     self.client.listen(self.on_message) 

    def on_message(self, result): 
     self.write_message(str(result.body)) 

    def close(self): 
     self.client.unsubscribe('test_channel') 
     self.client.disconnect() 

la sua multa nel caso di websocket ma come gestirlo nel comune metodo di post Tornado RequestHandler dice operazione polling lungo (modello di sottoscrizione-pubblicazione). Sto facendo una nuova connessione client in ogni metodo post di gestore di aggiornamento è questo l'approccio giusto ?? Quando ho controllato la console redis, vedo che i client aumentano in ogni nuova operazione di post.

enter image description here

Ecco un esempio del mio codice.

c = brukva.Client(host = '127.0.0.1') 
c.connect() 

class MessageNewHandler(BaseHandler): 
    @tornado.web.authenticated 
    def post(self): 

     self.listing_id = self.get_argument("listing_id") 
     message = { 
      "id": str(uuid.uuid4()), 
      "from": str(self.get_secure_cookie("username")), 
      "body": str(self.get_argument("body")), 
     } 
     message["html"] = self.render_string("message.html", message=message) 

     if self.get_argument("next", None): 
      self.redirect(self.get_argument("next")) 
     else: 
      c.publish(self.listing_id, message) 
      logging.info("Writing message : " + json.dumps(message)) 
      self.write(json.dumps(message)) 

    class MessageUpdatesHandler(BaseHandler): 
     @tornado.web.authenticated 
     @tornado.web.asynchronous 
     def post(self): 
      self.listing_id = self.get_argument("listing_id", None) 
      self.client = brukva.Client() 
      self.client.connect() 
      self.client.subscribe(self.listing_id) 
      self.client.listen(self.on_new_messages) 

     def on_new_messages(self, messages): 
      # Closed client connection 
      if self.request.connection.stream.closed(): 
       return 
      logging.info("Getting update : " + json.dumps(messages.body)) 
      self.finish(json.dumps(messages.body)) 
      self.client.unsubscribe(self.listing_id) 


     def on_connection_close(self): 
      # unsubscribe user from channel 
      self.client.unsubscribe(self.listing_id) 
      self.client.disconnect() 

Apprezzo se si fornisce alcuni esempi di codice per il caso simile.

+0

PubSub asincrono in Python utilizzando Redis, ZMQ, Tornado - https://github.com/abhinavsingh/async_pubsub –

risposta

2

si dovrebbero raggruppare le connessioni nella vostra app. dal momento che sembra che Brukva non supporti questo automaticamente (redis-py supporta questo, ma sta bloccando per sua natura quindi non va bene con il tornado), è necessario scrivere il proprio pool di connessioni.

il motivo è piuttosto semplice, però. qualcosa in questo senso (questo non è vero e proprio codice operativo):

class BrukvaPool(): 

    __conns = {} 


    def get(host, port,db): 
     ''' Get a client for host, port, db ''' 

     key = "%s:%s:%s" % (host, port, db) 

     conns = self.__conns.get(key, []) 
     if conns: 
      ret = conns.pop() 
      return ret 
     else: 
      ## Init brukva client here and connect it 

    def release(client): 
     ''' release a client at the end of a request ''' 
     key = "%s:%s:%s" % (client.connection.host, client.connection.port, client.connection.db) 
     self.__conns.setdefault(key, []).append(client) 

può essere un po 'più difficile, ma questa è l'idea principale.

9

Un po 'tardi ma, ho usato tornado-redis. Funziona con ioloop di tornado e la tornado.gen modulo

Installare tornadoredis

Può essere installato da pip

pip install tornadoredis 

o con setuptools

easy_install tornadoredis 

ma davvero non dovrebbe Fai quello. Puoi anche clonare il repository ed estrarlo. Quindi eseguire

python setup.py build 
python setup.py install 

Connetti a Redis

Il seguente codice va nella vostra main.py o equivalente

redis_conn = tornadoredis.Client('hostname', 'port') 
redis_conn.connect() 

redis.connect viene chiamato solo una volta. È una chiamata bloccante, quindi dovrebbe essere chiamata prima di avviare l'ioloop principale. Lo stesso oggetto di connessione è condiviso tra tutti i gestori.

Si potrebbe aggiungere alle vostre impostazioni dell'applicazione come

settings = { 
    redis = redis_conn 
} 
app = tornado.web.Application([('/.*', Handler),], 
           **settings) 

Usa tornadoredis

Il collegamento può essere utilizzato nei gestori a self.settings['redis'] o può essere aggiunto come una proprietà del BaseHandler e sottoclasse quella classe per altri gestori di richieste.

class BaseHandler(tornado.web.RequestHandler): 

    @property 
    def redis(): 
     return self.settings['redis'] 

Per comunicare con Redis, i tornado.web.asynchronous ei tornado.gen.engine decoratori sono utilizzati

class SomeHandler(BaseHandler): 

    @tornado.web.asynchronous 
    @tornado.gen.engine 
    def get(self): 
     foo = yield gen.Task(self.redis.get, 'foo') 
     self.render('sometemplate.html', {'foo': foo} 

Ulteriori informazioni

ulteriori esempi e altre caratteristiche come il pool di connessioni e tubazioni si possono trovare presso il github repo.

Problemi correlati