Hace poco tiempo que trabajo con colas de RabbitMQ, como cualquier otra mecanismo asíncrono tiene sus pros y contras.
Como cualquier otra tecnología, tendemos a acuñarla y aplicarla en absolutamente todos los niveles de negocio, obviando muchas veces alternativas más adecuadas y eficiente. Muchas veces cayendo en anti patrones, como puede ser el MQ over Batch (obviamente cuanto tiene sentido).
Por otro lado, también tenemos alternativas como pueden ser pub/sub. La aplicación de pub/sub o MQ depende de cómo escalará la aplicación y que tenemos que «ceder», para usar uno u otro. Espero hablar de esto en un post con más detalle.
Repositorio
Si os sirve de ayuda el código en el repositorio una estrellita no estaría de más
Enlace: Github repo (Golang)
Publicar mensajes RabbitMQ con GO
En este post sólo pondremos la parte de publicación de un mesare con go y seguramente en una parte 2, pondremos como consumir estos msg.
La estructura del proyecto, como sólo tiene este pequeño ejemplo es bastante simple:
Hablando de dependencia
Para esta pequeña aplicación, tan sólo necesitamos la dependencia de: github.com/streadway/amqp, que nos ofrece la gestión de conexiones, colas, publicación y consumo entre otras cosas.
module apascualco.com/rabbitmq-publisher-example
go 1.15
require github.com/streadway/amqp v1.0.0
Nuestro fichero main
El ejemplo es bastante sencillo y he evitado poner excesivo ruido para que sea practico al entender o utilizar en vuestro proyecto.
package main
import (
"log"
"time"
"github.com/streadway/amqp"
)
const QUEUE = "example_task_queue"
func connectRabbitMQ() *amqp.Connection {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/apascualco")
if err != nil {
log.Fatalf("Failed to connect to RabbitMQ: %s", err)
}
return conn
}
func openChannel(conn *amqp.Connection) *amqp.Channel {
c, err := conn.Channel()
if err != nil {
log.Fatalf("Failed to open a channel: %s", err)
}
return c
}
func declareQueue(channel *amqp.Channel) amqp.Queue {
q, err := channel.QueueDeclare(QUEUE, true, false, false, false, nil)
if err != nil {
log.Fatalf("Failed to declare a queue: %s", err)
}
return q
}
func publish(text string, channel *amqp.Channel, queue amqp.Queue) {
err := channel.Publish(
"",
queue.Name,
false,
false,
amqp.Publishing{
DeliveryMode: amqp.Persistent,
ContentType: "text/plain",
Body: []byte(text),
})
if err != nil {
log.Fatalf("Failed to publish a message: %s", err)
}
}
func generateMessages(count int) {
n := 0
for n < count {
n++
publish("apascualco : "+time.Now().String(),.channel,.queue)¬
}
}
func main() {
conn := connectRabbitMQ()
defer conn.Close()
channel := openChannel(conn)
defer channel.Close()
queue := declareQueue(channel)
publish("apascualco: "+time.Now().String(), channel, queue)
}
Si veis, la función main, podéis ver los pasos que se siguen para hacer la publicación:
- Obtener la conexión de rabbit
- Abrir un canal con la conexión obtenida
- Declarar una cola
- Publicar msg
How to use it
Para comprobar el funcionamiento, primero tenemos que tener un RabbitMQ, corriendo y acceso a el (para validar de forma más cómoda que se publica el msg).
Para ello, he añadido en el repo un Docker compone que levantara un rabbit y su herramienta de administración. Para lanzarlo tan solo tenéis que lanzar el comando
docker-composer up -d
Esto, nos levantará on Docker con el rabbit, preparado para ser utilizado. Podéis comprobarlo de la siguiente manera:
Si no os funciona el ejemplo por lo menos tenéis un RabbitMQ en local :).
Una vez que tenemos la infra necesaria, construimos el ejecutable lanzando y luego lo ejecutas:
go build cmd/publish_example.go
./publish_example
Esto provocará que si entramos en nuestro RabbitMQ, seguramente en la dirección: http://localhost:15672 (guest/guest)
Ya hemos publicado nuestro primer msg!