Getting Started with RabbitMQ in Golang: A Beginner's Guide

What is RabbitMQ, and Why Use It?

RabbitMQ is a message broker, which helps reliably send messages between applications. Imagine you’re building an online shop. You might need to notify users when their orders are confirmed, trigger stock checks, or send invoices. Without RabbitMQ, it’s easy to get overwhelmed if these tasks happen simultaneously. RabbitMQ can manage this by acting as a middleman, queuing up tasks and ensuring each one gets processed in order. This way, different parts of your system can talk to each other without overwhelming the whole app.

How Does RabbitMQ Work?

RabbitMQ follows a “producer-consumer” model:

  • Producers are applications or services that send messages.

  • Consumers are applications or services that receive those messages.

Messages get placed in a queue by the producer. Then, the consumer takes them out of the queue one by one and processes them.

Setting Up RabbitMQ

To get started, install RabbitMQ on your system. You can install it with Docker if you have that set up:

docker run -d --hostname rabbitmq --name my-rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management

Once RabbitMQ is running, it will be available at localhost:5672, and you can access the RabbitMQ management dashboard at localhost:15672 (username: guest, password: guest).

Installing RabbitMQ in Golang

You’ll need a RabbitMQ client library in Golang. Run:

go get github.com/streadway/amqp

This library lets Golang applications connect to RabbitMQ and send or receive messages.

A Real-World Example: Order Processing System

In this example, let's build a simplified order processing system. Our order service will place orders into a RabbitMQ queue, and a separate service will consume (or process) those orders.

1. Producing (Sending) Messages

The producer will be responsible for adding new orders to the queue.

 package main

import (
    "log"
    "github.com/streadway/amqp"
)

// Helper function to handle errors
func failOnError(err error, msg string) {
    if err != nil {
        log.Fatalf("%s: %s", msg, err)
    }
}

func main() {
    // Connect to RabbitMQ
    conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    // Create a channel
    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    // Declare a queue
    q, err := ch.QueueDeclare(
        "order_queue", // Queue name
        true,          // Durable (saves messages if server restarts)
        false,         // Delete when unused
        false,         // Exclusive
        false,         // No-wait
        nil,           // Arguments
    )
    failOnError(err, "Failed to declare a queue")

    // Message (order data)
    body := "Order: #12345"
    err = ch.Publish(
        "",         // Exchange
        q.Name,     // Routing key (queue name)
        false,      // Mandatory
        false,      // Immediate
        amqp.Publishing{
            ContentType: "text/plain",
            Body:        []byte(body),
        })
    failOnError(err, "Failed to publish a message")
    log.Printf(" [x] Sent %s", body)
}

This code does the following:

  1. Connects to RabbitMQ.

  2. Declares a queue called order_queue.

  3. Publishes a message (simulated order data) to the queue.

2. Consuming (Receiving) Messages

The consumer will listen to the order_queue and process each order as it’s received.

 package main

import (
    "log"
    "github.com/streadway/amqp"
)

// Helper function to handle errors
func failOnError(err error, msg string) {
    if err != nil {
        log.Fatalf("%s: %s", msg, err)
    }
}

func main() {
    // Connect to RabbitMQ
    conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
    failOnError(err, "Failed to connect to RabbitMQ")
    defer conn.Close()

    // Create a channel
    ch, err := conn.Channel()
    failOnError(err, "Failed to open a channel")
    defer ch.Close()

    // Declare the queue (it must exist)
    q, err := ch.QueueDeclare(
        "order_queue",
        true,
        false,
        false,
        false,
        nil,
    )
    failOnError(err, "Failed to declare a queue")

    // Receive messages from the queue
    msgs, err := ch.Consume(
        q.Name,
        "",
        true,  // Auto-acknowledge
        false, // Exclusive
        false, // No-local
        false, // No-wait
        nil,   // Args
    )
    failOnError(err, "Failed to register a consumer")

    // Process messages
    go func() {
        for d := range msgs {
            log.Printf("Received a message: %s", d.Body)
            // Here, you'd add order processing logic
        }
    }()

    // Keep the program running
    log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
    select {}
}

This code:

  1. Connects to RabbitMQ and declares the order_queue.

  2. Sets up a consumer to listen for messages on the queue.

  3. Logs each order received, where you could add code to process the order.


Running the Example

  1. Start the producer by running go run producer.go to send a new order message.

  2. Start the consumer with go run consumer.go to listen and process the orders.

Now, whenever you send a message from the producer, the consumer will receive and process it in real-time!


Final Thoughts

RabbitMQ is powerful because it can handle a lot of messages without your app slowing down or crashing. This is essential for scaling apps that rely on heavy messaging, like online stores, social media platforms, or even video streaming services.

Once you’ve mastered the basics, you can explore more complex RabbitMQ features like message routing, different types of exchanges, and even message prioritization!

0
Subscribe to my newsletter

Read articles from Oluwajuwon Falore directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Oluwajuwon Falore
Oluwajuwon Falore

I am a full-Stack (backend leaning) software developer. Experienced with all stages of the development cycle for dynamic web projects. Well-versed in programming languages including HTML5, CSS, JAVASCRIPT, NODEJS, GOLANG, REACTJS, PYTHON, ANGULAR and IONIC.