2011-09-18 28 views
12

Necesito desarrollar un feed de actividad reciente en tiempo real en django (con AJAX long-polling), y me pregunto cuál es la mejor estrategia para el lado del servidor.Técnica de notificación ligera

Pseudocódigo:

def recent_activity_post_save(): 
    notify_view() 

[in the view] 
while not new_activity(): 
    sleep(1) 
return HttpResponse(new_activity()) 

La primera cosa que viene a la mente está consultando la base de datos cada segundo. No factible. Otras opciones:

  1. utilizando el caché como un servicio de notificación
  2. usando una herramienta especializada, como el apio (prefiero no lo hacen, ya que parece un exceso)

Cuál es la mejor camino a seguir aquí?

Respuesta

5

Yo sugeriría hacer que sea sencillo ...

Crear una tabla de base de datos para almacenar los eventos, insertar en esa mesa en su caso, a continuación, sólo poner en práctica una técnica simple de ajax de votación para golpear el servidor cada x segundos en el lado del cliente.

Me preocupan otras soluciones que consideren el uso de un enfoque de notificación push o el uso de un almacén de datos noSql. Es mucho más complicado que un sistema de notificación de extracción tradicional que utiliza las herramientas integradas en el marco de trabajo de Django, y salvo excepciones muy raras, es excesivo. A menos que requiera específicamente una solución estricta en tiempo real, manténgala simple y use las herramientas que ya existen en el marco, y para las personas con objeciones basadas en el rendimiento de la base de datos o de la red, todo lo que tengo que decir es que la optimización prematura es la raíz de todo mal

Cree un modelo que contenga datos de actividad recientes específicos para su aplicación y luego, siempre que su aplicación haga algo que deba registrar nueva actividad, puede simplemente insertarla en esta tabla.

Su vista sería simplemente como cualquier otra vista, tirando de las primeras filas x de esta tabla RecentActivity (opcionalmente basada en parámetros de consulta y lo que sea).

Luego, en el lado del cliente, tendría un simple sondeo ajax que golpea su vista cada x segundos. No hay escasez de plugins complicados y tecnologías que se pueden utilizar, pero escribir su propio no es tan complicado, ya sea:

function simplePoll() { 
    $.get("your-url", {query-parameters}, function(data){ 
    //do stuff with the data, replacing a div or updating json or whatever 
    setTimeout(simplePoll, delay); 
    }); 
} 

Mi opinión es que los problemas de rendimiento no son realmente problemas hasta que su sitio es lo suficientemente exitoso para ellos ser un problema Una base de datos relacional tradicional puede escalar bastante bien hasta que empiece a alcanzar el nivel de éxito como Twitter, Google, etc. La mayoría de nosotros no estamos en ese nivel :)

0

Puede utilizar un disparador (disparado cada vez que se realiza una nueva publicación). Este disparador podría escribir, por ejemplo, un nuevo archivo en un directorio de sondeo con los datos necesarios (por ejemplo, la clave principal). Su python podría simplemente mirar esa carpeta para nuevas creaciones de archivos sin tener que tocar la base de datos hasta que aparezca un nuevo archivo.

1

Puede utilizar una solución de cometa, como el Ape project. Este tipo de proyecto está diseñado para enviar datos en tiempo real al navegador, y puede hacer uso de los navegadores modernos que ofrecen los conectores web.

0

Si buscas una solución de cometa entonces you could use orbited. Déjame advertirte que, aunque es una solución bastante específica, es muy difícil encontrar una buena documentación sobre cómo implementar y usar orbited en entornos de producción.

0

Aquí hay una discusión similar, respondiendo desde la perspectiva del lado del servidor: Making moves w/ websockets and python/django (/ twisted?) , la respuesta más importante es this one.

También hay this answer, lo que apunta a una alternativa de aspecto muy sólido para intentar esto desde Django.

Si realmente desea que esto se aplique desde su aplicación Django existente, no haga esto en el servidor. Mantener esa toma de conexión HTTP a la conexión de un solo navegador es una forma rápida de romper su aplicación. Dos alternativas razonables son: explorar las diversas opciones de socket web (como la anterior que utiliza Pyramid para alojar el servicio), o hacer que el navegador envíe una solicitud de sondeo periódicamente al servidor en busca de actualizaciones.

+1

Esto es generalmente un buen consejo, pero la pregunta sí lo dijo específicamente "en django (con AJAX long-polling)". – dkamins

2

¿Ha considerado utilizar las señales? Podría enviar una señal en recent_activity_post_save() y podría haber un oyente que almacena la información en caché.

La vista solo se referiría a la memoria caché para ver si hay nuevas notificaciones. Por supuesto que no necesita señales, pero en mi humilde opinión sería un poco más limpio de esa manera, ya que podría agregar más "controladores de notificación".

Esto parece óptimo porque no necesita sondear el DB (carga artificial), las notificaciones son "visibles" casi de inmediato (solo después del tiempo requerido para procesar las señales e interactuar con el caché).

Así que el pseudocódigo se vería así:

# model 
def recent_activity_post_save(): 
    post_save_signal.send() 

# listener 
def my_handler(...): 
    cache.set('notification', ....) 

post_save_signal.connect(my_handler) 

# view 
def my_view(request): 
    new_notification = None 
    while not new_notification: 
     sleep(1) 
     new_notification = cache.get('notification') 
    return HttpResponse(...) 
+0

esto es exactamente lo que estoy usando ahora; también me parece óptimo, pero estaba buscando otras opiniones sobre este tema. +1 –

+0

Me gustó esta solución hasta que vi la línea 'while not new_notification' ... no podría teóricamente colgar indefinidamente en una solicitud, presumiblemente una solicitud de votación ajax de algún tipo, mientras espera una nueva notificación para entrar? ¿No sería mejor devolver un conjunto de datos vacío de la vista si el caché estaba vacío? –

+0

@DMactheDestroyer que era una especie de pseudocódigo, por supuesto, devuelve un resultado vacío después de 30 segundos más o menos si no hay actividad nueva. –

0

Usted debe decidir si prefiere ir con una arquitectura de "pull" o "empuje" para la entrega de sus mensajes, ver esto post on quora! Si desea buscar una solución que "empuje" las notificaciones a sus receptores, los sistemas basados ​​en caché/nosql son preferibles ya que no producen una carga tan alta para muchas acciones de escritura.

Redis, por ejemplo, con su conjunto de datos ordenados/listas le ofrece una gran cantidad de ejemplos. Ver por ej. this post (aunque no es python) para tener una idea. ¡También podría buscar colas de mensajes "reales" como RabbitMQ por ejemplo!

Para la conexión con el cliente, las otras publicaciones aquí ya deberían haberle dado algunas ideas sobre cómo usar estructuras retorcidas y similares.

Y el apio siempre puede ser una buena herramienta, por ejemplo. tener toda la escritura en las actividades de los usuarios en un trabajo asincrónico!

+0

gracias por la idea; Estaba buscando una solución _lightweight_, porque no tiene sentido instalar una base de datos NoSQL para una sola página en un sitio, ¿verdad? –

0

No veo la necesidad de limitarse al uso de largas sondas si eso no es realmente necesario. Hay bibliotecas escritas para aprovechar la mejor opción posible (puede ser una encuesta corta, un sondeo largo, websockets o incluso un pequeño complemento flash si ninguna de las opciones anteriores está disponible). Node.js tiene una de las mejores bibliotecas para ese tipo de trabajo, llamada Socket.IO, pero afortunadamente también hay dos implementaciones de Python disponibles, gevent-socketio y tornadio, pero luego se construye sobre el marco de tornado, por lo que posiblemente esté fuera de pregunta.

Si le conviene, puede combinarlos con parte de la base de datos NoSQL (documento), que se ha demostrado que es mucho más rápida y liviana que las bases de datos relacionales. Hay muchas opciones, incluyendo CouchDB, MongoDB, Redis, ... La combinación de Socket.IO y DB basada en documentos ha demostrado ser rápida, liviana y confiable.

Aunque he visto que ya ha considerado NoSQL en los comentarios, mi opinión personal es que si necesita una solución rápida y fácil, y las opciones anteriores le convengan, esta es la mejor oportunidad que puede tomar.