If you are looking for a way to integrate you Golang application with RabbitMQ queue then you've found it!
What is RabbitMQ?
RabbitMQ is a highly available message queue build for high troughput and low latency supporting multiple protocols. What does that mean?
Message queue
Simply put, it's a service to which you can send a message containing some data and read this message any time. In addition you can send messages in parallel and at the same time read them, also in parallel. Message queue is a service that allows you to have control over the flow of data in your application. Scale the infrastructure that handles it's processing and make sure no data is lost.
Highly available
RabbitMQ supports data replication, which means that it's able to copy the data you send to it to multple hosts. In case of a failure of one of the nodes, your data is safe and the processing is uninterrupted.
High throughput
RabbitMQ can handle multiple millions of messages per second.
Low latency
Each message in RabbitMQ is available for processing immediately, if you provide enough infrastructure that can answer the load, RabbitMQ will not be a bottleneck.
Multiple protocols
RabbitMQ can speak multiple protocols, AMQP, STOMP, MQTT, HTTP/Websocket
RabbitMQ cluster on Docker
I have already described in detail how to setup RabbitMQ cluster with Docker. Please read the below article for more details: Klaster RabbitMQ na Dockerze z Nodejs w 5 minut .
Below is an excerpt of the command to be run in order to setup a cluster.
# pull docker images
docker pull 3.6.6-management
# start docker image and attach to the shell
docker run --hostname rabbit --name rabbit --rm -ti --net="host" rabbitmq:3.6.6-management /bin/bash
# start three distincs RabbitMQ processes identified by different names
RABBITMQ_NODE_PORT=5672 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15672}]" RABBITMQ_NODENAME=rabbit rabbitmq-server -detached
RABBITMQ_NODE_PORT=5673 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15673}]" RABBITMQ_NODENAME=hare rabbitmq-server -detached
RABBITMQ_NODE_PORT=5674 RABBITMQ_SERVER_START_ARGS="-rabbitmq_management listener [{port,15674}]" RABBITMQ_NODENAME=john rabbitmq-server -detached
# join `hare` node to `rabbit` cluster
rabbitmqctl -n hare stop_app
rabbitmqctl -n hare join_cluster rabbit@`hostname -s`
rabbitmqctl -n hare start_app
# join `john` node to `rabbit` cluster
rabbitmqctl -n john stop_app
rabbitmqctl -n john join_cluster rabbit@`hostname -s`
rabbitmqctl -n john start_app
Connect to RabbitMQ with Golang. Create Producer script
package main
import (
"log"
"github.com/streadway/amqp"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
q, err := ch.QueueDeclare(
"hello", // name
false, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
body := "Hello World!"
err = ch.Publish(
"", // exchange
q.Name, // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body),
})
log.Printf(" [x] Sent %s", body)
failOnError(err, "Failed to publish a message")
}
Create Consumer script
package main
import (
"log"
"github.com/streadway/amqp"
)
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}
func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
q, err := ch.QueueDeclare(
"hello", // name
false, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
forever := make(chan bool)
go func() {
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
}
}()
log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
<-forever
}
Run both scripts
Now that we have our script ready we can run each of them. Create two separate files as distinct Go modules. Run `send.go` first to produce a message
/go/src/rabbit-example/producer# go run send.go
2020/12/05 21:14:14 [x] Sent Hello World!
And the run `receive.go` to consume produced message
/go/src/rabbit-example/consumer# go run receive.go
2020/12/05 21:14:39 [*] Waiting for messages. To exit press CTRL+C
2020/12/05 21:14:39 Received a message: Hello World!
That's it we have implemented a RabbitMQ into Go code in 5 minutes, plain and simple. RabbitMQ has many different options and setting and you should spend some time reading the documentation to fully understand how it works and what should be the perfect setting for your use case.
Thanks for reading, I want to provide more articles about implementing RabbitMQ in Golang applications, highlighting especially low latency workers with multiple queues. Let me know if you are interested!
Similar searches: rabbitmq golang / go queue rabbitmq / implement rabbitqm in golang application