Initial commit
[blog.git] / posts / 151.html
1 title: pyrabbit, experimentando con RabbitMQ
2 date: 2013-10-31 08:29
3 ---
4 <div>
5 <a href="http://www.jsancho.org/wp-content/uploads/2013/10/RabbitMQ.sh-600x600.png"><img src="http://www.jsancho.org/wp-content/uploads/2013/10/RabbitMQ.sh-600x600-300x300.png" alt="RabbitMQ" width="300" height="300" class="alignleft size-medium wp-image-596" /></a>
6
7 <p>Llevo ya un tiempo probando <a href="http://www.rabbitmq.com/">RabbitMQ</a>, un sistema de mensajería para aplicaciones basado en colas, muy potente y escalable, desarrollado con <a href="http://es.wikipedia.org/wiki/Erlang">Erlang</a>. Para saber un poco más de este lenguaje de programación recomiendo leer <a href="http://learnyousomeerlang.com/">Learn You Some Erlang for Great Good!</a> Cuando conoces un poco este lenguaje comprendes por qué lo han usado para programar RabbitMQ, ya que da la impresión de que Erlang fue diseñado expresamente para crear este tipo de sistemas.</p>
8
9 <p>Hay una cosa que no me ha gustado demasiado de RabbitMQ, y es que es el propio sistema de mensajería el que decide para quién es un determinado mensaje. Me explico. Supongamos que tenemos una cola que recibe mensajes con trabajos a realizar y tenemos dos procesos suscritos a la cola para realizar esos trabajos. Para ello, los procesos se suscriben a la cola y es RabbitMQ el que manda los mensajes al proceso que crea conveniente. Si el proceso que recibe el mensaje no puede atenderlo en ese momento, por las razones que sean, debe cancelar la recepción para que RabbitMQ pueda reencolar el mensaje y otro proceso pueda recibirlo.</p>
10
11 <p>Para este tipo de cosas yo prefiero usar peticiones tipo "long polling" con posibilidad de especificar un timeout, de forma que sea el propio proceso el que pida mensajes al servidor. Por supuesto, igual puede ocurrir que el proceso pierda la conexión, no pueda atender al mensaje, etc, con lo que también deberíamos cancelar la recepción para el reencolado del mensaje, pero ya resulta más extraño, y el código de los procesos resulta más legible.</p>
12
13 <p>He desarrollado una pequeña librería en Python, <a href="https://gitorious.org/pyrabbit/">pyrabbit</a>, que por debajo usa <a href="https://pypi.python.org/pypi/pika/">Pika</a>, una implementación del protocolo AMPQ que nos sirve para conectar con RabbitMQ y comunicarnos con las colas. Con pyrabbit es posible realizar estas operaciones de forma muy sencilla.</p>
14
15 <pre>import pyrabbit
16 connection = pyrabbit.Connection('localhost')
17
18 # Enviar mensaje a mi_cola y leerlo después con un timeout de diez segundos
19 connection.mi_cola.send("hola")
20 m = connection.mi_cola.receive(timeout=10)
21 print m.body   # Esto imprime 'hola'
22
23 # Confirmamos que el mensaje ha sido procesado y no es necesario reencolarlo
24 m.ack()
25
26 # Tambien es posible enviar mensajes y esperar confirmación con un timeout
27 # Supongamos que tenemos un proceso que calcula sumas
28 r = connection.cola_de_sumas.send("[2,3]", wait_response=True, timeout=5)
29 print r.body   # Si el proceso ficticio que suma números funciona, obtendremos "5"
30
31 # Cerramos
32 connection.close()</pre>
33
34 <p>Con pyrabbit puedo comunicar programas de forma sencilla y el código es muy legible, pero no me gusta la forma en que tengo implementada la recepción de mensajes, ya que estoy solicitando mensajes al servidor hasta que me devuelve alguno o hasta que salta el timeout. Para no penalizar demasiado, incluyo un retardo incremental con el que acabo pidiendo mensajes cada segundo si la espera es demasiado larga, pero aún así no me acaba. Si alguien sabe una forma de pedir mensajes a RabbitMQ de tipo similar a <a href="http://es.wikipedia.org/wiki/Tecnolog%C3%ADa_Push#Long_polling">long polling</a>, le estaría muy agradecido.</p>
35 </div>