Implementing Pub/Sub in Go with Redis for Real-Time Apps

Pub/Sub (Publish/Subscribe) is a messaging pattern where the sender (publisher) doesn't send messages directly to specific receivers, messages are categorized into channels.

Pub/Sub in Go with Redis for Real-Time Apps

Real-time experiences like chat systems, live dashboards, and notifications are now a fundamental part of modern applications. Redis Pub/Sub, when paired with Go's concurrency and performance, offers a fast and efficient way to build such features. In this article, we'll walk through building a simple real-time message broadcasting system using Go and Redis Pub/Sub.

>> Read more: Go for Web Development: How Top Companies Benefit from Golang?

What is Pub/Sub?

Publish/Subscribe (Pub/Sub) is a messaging pattern where the sender (publisher) does not send messages directly to specific receivers. Instead, messages are categorized into channels. Receivers (subscribers) subscribe to channels and receive any message published to those channels.

Key Concepts:

  • Publisher: Sends messages to a channel.
  • Subscriber: Listens to messages on one or more channels.
  • Channel: A named stream of messages.

Why Redis?

Redis is an open-source, in-memory data structure store, often used as a database, cache, and message broker. It's known for its blazing speed and minimal latency—two qualities that are essential for real-time systems.

Why Use Redis for Pub/Sub?

  • High Performance: Redis operates entirely in memory, making it ideal for high-throughput, low-latency use cases like messaging.
  • Simplicity: Setting up Redis for Pub/Sub is straightforward and requires minimal configuration.
  • No External Broker Required: If your application already uses Redis for caching or data storage, Pub/Sub comes built-in—eliminating the need to add another messaging service.
  • Multi-language Support: Redis clients exist for nearly every language, including robust support for Go, enabling seamless integration.
  • Decoupled Architecture: Redis Pub/Sub allows services to communicate asynchronously, promoting a loosely coupled architecture.

When to Use It

Redis Pub/Sub is perfect for lightweight, ephemeral real-time communication like:

  • Live chat and notifications
  • Real-time analytics and metrics
  • System monitoring and alerts

Limitations

  • No Message Durability: Messages are not stored. If a subscriber is offline, it will miss messages.
  • No Acknowledgments or Retries: There’s no built-in mechanism for ensuring message delivery or processing.
  • Not Ideal for Complex Workflows: Use Redis Streams, Kafka, or RabbitMQ for message queuing, persistence, and consumer groups.

For more robust requirements, Redis Streams or other messaging systems like Kafka or NATS may be better suited.

Setting Up Your Go Environment

Initialize Your Project:

clike
go mod init redis-pubsub-go

Install Redis Client:

clike
go get github.com/redis/go-redis/v9

Create Redis Client:

clike
package main

import (
    "context"
    "github.com/redis/go-redis/v9"
    "log"
    "time"
    "fmt"
)

var ctx = context.Background()

func createClient() *redis.Client {
    return redis.NewClient(&redis.Options{
        Addr:     "redis:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })
}

Publisher Function

Here’s a simple function to publish messages:

clike
func publishMessage(rdb *redis.Client, channel string, message string) {
    err := rdb.Publish(ctx, channel, message).Err()
    if err != nil {
        log.Fatalf("Could not publish: %v", err)
    }
    log.Printf("Published: %s", message)
}

Subscriber Function

This function listens for messages on a specified channel:

clike
func subscribeChannel(rdb *redis.Client, channel string) {
    pubsub := rdb.Subscribe(ctx, channel)
    defer pubsub.Close()

    ch := pubsub.Channel()
    log.Printf("Subscribed to channel: %s", channel)

    for msg := range ch {
        log.Printf("Received message: %s", msg.Payload)
    }
}

Demo: Real-Time Notifications

Simulate Publisher:

clike
func main() {
    rdb := createClient()

    for i := 1; i <= 5; i++ {
        publishMessage(rdb, "notifications", fmt.Sprintf("Message #%d", i))
        time.Sleep(2 * time.Second)
    }
}

Simulate Subscriber:

clike
func main() {
    rdb := createClient()
    subscribeChannel(rdb, "notifications")
}

Run one instance as publisher, and another as subscriber. You’ll see real-time message broadcasting via Redis.

Expected Output

Publisher logs:

clike
Published: Message #1
Published: Message #2
Published: Message #3
...

Subscriber logs:

clike
Subscribed to channel: notifications
Received message: Message #1
Received message: Message #2
Received message: Message #3
...

Dockerize A Golang App

To simplify local development, you can use Docker Compose to run both Redis and your Go app.

Dockerfile

clike
# syntax=docker/dockerfile:1
FROM golang:1.21-alpine

WORKDIR /app
COPY . .
RUN go mod tidy && go build -o app

CMD ["./app"]

docker-compose.yml

clike
version: '3.8'
services:
  redis:
    image: redis:7
    container_name: redis-server
    ports:
      - "6379:6379"
    restart: unless-stopped

  app:
    build: .
    container_name: go-pubsub-app
    depends_on:
      - redis
    restart: on-failure

How to Run It?

  1. Make sure you have Docker installed.
  2. Place your Go app files, Dockerfile, and docker-compose.yml in the project root.
  3. Run the following command:
clike
docker-compose up --build

This will start Redis and your Go app together. You can split the subscriber and publisher logic into separate services if needed.

Make sure your Go code connects to Redis using redis:6379 since it's the internal hostname within Docker Compose.

Best Practices

  • Use context.WithCancel() for better control over long-running subscriptions.
  • Handle reconnection and retries gracefully.
  • Avoid using Redis Pub/Sub for mission-critical messaging needs—consider Redis Streams or Kafka for persistence.

>> Explore more: Top 10 Most Popular NoSQL Databases for Developers

Conclusion

With just a few lines of Go and Redis, you can set up a powerful real-time messaging system. Redis Pub/Sub is a great starting point for building lightweight features such as chat systems, notifications, and live updates. For more scalable and persistent systems, consider Redis Streams or a dedicated message broker.

>>> Follow and Contact Relia Software for more information!

  • golang
  • coding