Learn RabbitMQ - Producers & Consumers - Hello World
Episode 4 of 33

Learn RabbitMQ - Producers & Consumers - Hello World

Time to write your first code with RabbitMQ. In this episode you create a simple producer and consumer using Python pika, Node.js amqplib, and Go amqp091-go, then learn the best practices for managing connections, channels, heartbeats, and graceful shutdown.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

This is the happiest moment in this series: you will write your first program that truly communicates through RabbitMQ. We start with the simplest pattern — one producer sending a "Hello World" message to a queue, and one consumer printing it out.

Even though it's simple, this episode contains important foundations that will not change throughout your career: how to open a connection, how to create a channel, how to publish a message, and how to process incoming messages. Mistakes in connection and channel management at this stage will become serious problems in production.

We show implementations in the three most popular languages — Python with pika, Node.js with amqplib, and Go with amqp091-go. Pick the language you're most comfortable with, but try to understand the common pattern: they all share an identical flow.

Simple Message Flow

Your First Producer

Install the client library in your language of choice. For Python:

Install pika
pip install pika

Then write the producer. The producer opens a connection, creates a channel, declares the queue, and publishes a message:

PythonHello World producer (pika)
import pika
 
connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
 
channel.queue_declare(queue="hello")
 
channel.basic_publish(exchange="", routing_key="hello", body=b"Hello World")
print("pesan terkirim")
connection.close()

Notice that here routing_key plays the role of the queue name, because we use the default exchange (an empty exchange). Exchange details will be covered in episode 6.

Your First Consumer

The consumer uses a callback that is invoked every time a message arrives:

PythonHello World consumer (pika)
import pika
 
connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
 
channel.queue_declare(queue="hello")
 
def callback(ch, method, properties, body):
    print(f"menerima: {body}")
 
channel.basic_consume(queue="hello", on_message_callback=callback, auto_ack=True)
print("menunggu pesan...")
channel.start_consuming()

The channel.start_consuming function blocks the program and keeps listening for messages. auto_ack=True tells the broker that the message is considered processed immediately without a manual ack.

Examples in Other Languages

Producer and Consumer in Node.js

For Node.js, install amqplib then write the producer:

Install amqplib
npm install amqplib
JSHello World producer (amqplib)
const amqp = require("amqplib");
 
async function main() {
  const conn = await amqp.connect("amqp://localhost");
  const ch = await conn.createChannel();
  await ch.assertQueue("hello");
  ch.sendToQueue("hello", Buffer.from("Hello World"));
  console.log("pesan terkirim");
  await conn.close();
}
 
main();

amqp.connect returns a promise, and assertQueue declares the queue if it doesn't exist yet. In Node.js, we'll improve the async pattern above with connection recovery in episode 28.

Producer in Go

For Go, install the official package amqp091-go:

Install amqp091-go
go get github.com/rabbitmq/amqp091-go
Hello World producer (amqp091-go)
package main
 
import (
	"log"
 
	amqp "github.com/rabbitmq/amqp091-go"
)
 
func main() {
	conn, err := amqp.Dial("amqp://localhost")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()
 
	ch, err := conn.Channel()
	if err != nil {
		log.Fatal(err)
	}
	defer ch.Close()
 
	err = ch.Publish("", "hello", false, false, amqp.Publishing{Body: []byte("Hello World")})
	if err != nil {
		log.Fatal(err)
	}
	log.Println("pesan terkirim")
}

Notice that Publish in Go does not declare the queue automatically — the declaration must be done explicitly. This is a reminder that declaring queues is the application's responsibility, not the broker's.

Best Practices for Connection Management

Connection Pooling and One Channel per Thread

One thing to always remember: a connection is an expensive resource, a channel is a cheap resource. An application should use one or a few shared connections, and create a new channel for each concurrent task. In Python, if you use BlockingConnection in many threads, create one connection per thread. In Node.js and Go, a single connection can be used concurrently because its channels are thread-safe.

Heartbeat and Graceful Shutdown

Every connection must set up a heartbeat — a periodic ping so the broker knows the client is still alive. The RabbitMQ default heartbeat is 60 seconds. If the client doesn't send data for too long, the broker will disconnect what it considers a dead connection.

For graceful shutdown, the consumer must stop processing new messages, then close the channel and connection in the right order:

PythonCorrect shutdown (pika)
channel.stop_consuming()
channel.close()
connection.close()

connection.close() must be called after all channels are closed, so the broker releases resources cleanly.

Warning

Never close the connection inside a consumer callback without handling the message currently being processed. The message could be lost or acked twice. Always think through the shutdown order in episode 5 when we discuss acknowledgment.

Conclusion

In episode 4 you wrote your first producer and consumer in Python, Node.js, and Go; understood the connection-channel-publish-consume flow; and learned best practices for connection management, heartbeats, and clean shutdown.

Key takeaways:

  • The producer publishes to an exchange; the routing key points to the queue on the default exchange.
  • The consumer works with a callback that is invoked when a message arrives.
  • One connection is used for many channels; don't waste connections.
  • Heartbeats keep connections alive and detect when they die.
  • Graceful shutdown closes the consumer, then the channel, then the connection.
  • auto_ack=True makes demos easier, but is dangerous for production.

In the next episode we will build work queues — distributing heavy tasks to many workers with round-robin, using manual acknowledgment so messages aren't lost when a worker crashes, and setting prefetch with QoS so each worker works within its capacity. This concept is the foundation of every task processing system in the real world!

Learn RabbitMQ - Producers & Consumers - Hello World | Learn RabbitMQ