Wednesday, November 11, 2020

Redis Pub/Sub using go-redis library

 



In this post we will review the usage of Redis Pub/Sub using a GO code that uses the go-redis library.


Our main code initiates a connection to Redis, and then starts two subscribers, and two publishers. Since we start the subscribers and the publishers as GO routines, we add sleep of 5 seconds to avoid immediate termination of the process.


package main

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

const channel = "my-channel"

func main() {
address := "127.0.0.1:5555"
options := redis.Options{
Addr: address,
Password: "",
DB: 0,
}
client := redis.NewClient(&options)

go subscriber(1,client)
go subscriber(2,client)
go publisher(1,client)
go publisher(2,client)
time.Sleep(5 * time.Second)
}



The subscriber loops forever on the ReceiveMessage calls, and prints them to the STDOUT.


func subscriber(subscriberId int, client *redis.Client) {
ctx := context.Background()
pubsub := client.Subscribe(ctx, channel)
for {
message, err := pubsub.ReceiveMessage(ctx)
if err != nil {
panic(err)
}
fmt.Printf("subscriber %v got notification: %s\n",subscriberId, message.Payload)
}
}


And each of the publishers sends 3 messages to the channel.


func publisher(publisherId int, client *redis.Client) {
ctx := context.Background()
for i := 0; i < 3; i++ {
client.Publish(ctx, channel, fmt.Sprintf("Hello #%v from publisher %v", i, publisherId))
}
}


Once we run this small application, we get the following output:


subscriber 1 got notification: Hello #1 from publisher 1
subscriber 2 got notification: Hello #1 from publisher 1
subscriber 2 got notification: Hello #1 from publisher 2
subscriber 2 got notification: Hello #2 from publisher 2
subscriber 1 got notification: Hello #1 from publisher 2
subscriber 1 got notification: Hello #2 from publisher 2
subscriber 2 got notification: Hello #2 from publisher 1
subscriber 1 got notification: Hello #2 from publisher 1


But, wait.

We have 2 producers, 2 subscribers, and 3 messages. That's 2*2*3 = 12 expected messages to the STDOUT, but we got only 8 messages.

The reason for that is the Redis Pub/Sub behavior, which does behave as a queue. Instead only the active subscribers will get notified with messages in the channel. As the subscribers are not active yet when the first messages are sent, these messages are not sent to any subscriber.

If we wanted all of the messages to be received, we should wait (e.g. sleep), after launching the subscribers GO routines, and before starting the publishers.


Final Note


In this post we have reviewed the Redis Pub/Sub usage, and its behavior.

When running Pub/Sub in a Redis cluster, the messages will be broadcast to all of the cluster nodes, which might be a performance issue. In case this is indeed a performance issue, it is possible to consider the Redis streams instead.

No comments:

Post a Comment