The code snippet below is from a worker that consumes messages from a queue. For now, just imagine that there’s another Go program that publishes messages to this.
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
false, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
var forever chan struct{}
go func() {
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
dotCount := bytes.Count(d.Body, []byte("."))
t := time.Duration(dotCount)
time.Sleep(t * time.Second)
log.Printf("Done")
// d.Ack(false)
}
}()
We ran the publisher Go program that sent the ‘hello’ payload
go run .
2026/01/12 20:47:01 [x] Sent hello
Then we ran the worker (with snippet from above) that received the same message payload.
go run ./worker
2026/01/12 20:47:05 [*] Waiting for messages. To exit press CTRL+C
2026/01/12 20:47:05 Received a message: hello
2026/01/12 20:47:05 Done
Now when we list the unacknowledged message, we can see that there’s one. This is because since we set auto-acknowledge to false, we need to mark a message acknowledged once it’s processed. Every time the consumer client is rerun, it will pick up this message but not mark is as acknowledged. To fix this, just uncomment d.Ack... above.
docker exec -it rabbitmq rabbitmqctl list_queues name messages_ready messages_unacknowledged
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
name messages_ready messages_unacknowledged
task_queue 0 1