redis

package
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 6 Imported by: 0

README

redis — provides a Redis-backed Broadcaster for socketio, enabling multi-node scale-out

Go Reference

Package redis provides a Redis-backed Broadcaster for socketio, enabling multi-node scale-out: broadcasts are relayed between server instances over Redis pub/sub so a message emitted on one node reaches sockets connected to any node. It is the Go counterpart of the Node.js @socket.io/redis-adapter, and it speaks the Redis RESP protocol directly using only the standard library — no third-party client and no cgo:

bc, _ := redis.New(redis.Options{Addr: "localhost:6379", Channel: "socket.io"})
io.SetBroadcaster(bc) // io is a *socketio.Server

A single socketio.Server keeps its room and socket membership in memory, so a broadcast only reaches clients connected to that one process. Once you run more than one instance behind a load balancer — for horizontal scaling or high availability — clients are spread across processes and an in-memory broadcast no longer reaches everyone. Install this Broadcaster on every node and each call to io.Emit, io.To(room).Emit, and the other broadcast forms is instead published once to Redis and delivered to the local sockets of every node that receives it. Reach for this package as soon as you scale past a single server.

Install

go get github.com/malcolmston/socketio@v0.5.0
import "github.com/malcolmston/socketio/redis"

Usage

This is the package's own ExampleNew, so it compiles and its output is asserted on every go test ./redis/.

bc, err := redis.New(redis.Options{
		Addr:    "localhost:6379",
		Channel: "socket.io",
	})
	if err != nil {
		log.Fatal(err)
	}
	defer bc.Close()

	io := socketio.New()
	io.SetBroadcaster(bc)

	io.To("room1").Emit("news", "hello cluster")

Exported surface

Types
Type What it is
Broadcaster Broadcaster relays socketio broadcasts over Redis pub/sub.
Options Options configures the Redis broadcaster.
Broadcaster — constructors and methods
Signature What it does
func New(opts Options) (*Broadcaster, error) New connects to Redis, subscribes to the broadcast channel, and returns a Broadcaster ready to install with server.SetBroadcaster.
func (b *Broadcaster) Close() error Close implements socketio.Broadcaster.
func (b *Broadcaster) OnMessage(fn func([]byte)) OnMessage implements socketio.Broadcaster.
func (b *Broadcaster) Publish(data []byte) error Publish implements socketio.Broadcaster: it PUBLISHes data to the channel.
Constants

MaxArrayLength, MaxBulkLength

Variables

ErrClosed, ErrReplyTooLarge

Full signatures, doc comments and every runnable example are on pkg.go.dev.

Deviations from upstream

Deliberate differences for this package, where any exist, are recorded in the module-wide API-DEVIATIONS.md.

License

MIT, as part of github.com/malcolmston/socketio. An independent re-implementation, not affiliated with or endorsed by the original project.

Documentation

Overview

Package redis provides a Redis-backed Broadcaster for socketio, enabling multi-node scale-out: broadcasts are relayed between server instances over Redis pub/sub so a message emitted on one node reaches sockets connected to any node. It is the Go counterpart of the Node.js @socket.io/redis-adapter, and it speaks the Redis RESP protocol directly using only the standard library — no third-party client and no cgo:

bc, _ := redis.New(redis.Options{Addr: "localhost:6379", Channel: "socket.io"})
io.SetBroadcaster(bc) // io is a *socketio.Server

A single socketio.Server keeps its room and socket membership in memory, so a broadcast only reaches clients connected to that one process. Once you run more than one instance behind a load balancer — for horizontal scaling or high availability — clients are spread across processes and an in-memory broadcast no longer reaches everyone. Install this Broadcaster on every node and each call to io.Emit, io.To(room).Emit, and the other broadcast forms is instead published once to Redis and delivered to the local sockets of every node that receives it. Reach for this package as soon as you scale past a single server.

It works by holding two Redis connections: one for PUBLISH and one that issues SUBSCRIBE and runs a background receive loop. When the server broadcasts, it serializes the target namespace, rooms, exclusions, event name, and arguments and calls Publish, which PUBLISHes the bytes to the configured channel. Redis fans that message out to every subscriber, including the publisher, and the receive loop hands each incoming payload to the handler the server registered through OnMessage — which decodes it and re-emits to that node's local sockets. Because pub/sub echoes to the sender, the originating node delivers its own broadcast through exactly the same path, so no node is special-cased.

New connects, authenticates (AUTH) and selects a database (SELECT) if configured, subscribes, and returns a *Broadcaster ready to pass to server.SetBroadcaster; Options carries Addr, Channel, Password, DB, and an optional Dial hook used by tests to substitute an in-memory connection. The three methods that satisfy socketio.Broadcaster — Publish, OnMessage, and Close — are safe for concurrent use: Publish serializes writes on the publish connection with a mutex, and OnMessage/Close guard shared state with their own lock. Close is idempotent and tears down both connections, ending the receive loop.

Delivery inherits Redis pub/sub semantics, which callers should understand. Pub/sub is fire-and-forget and at-most-once: messages are not persisted or queued, so a node that is down or momentarily disconnected misses whatever was published while it was unavailable — matching the behavior of the Node redis adapter. Publish returns an error only if the local write to Redis fails, not if a remote subscriber never receives the message. The RESP codec here implements just the commands this adapter needs (SUBSCRIBE, PUBLISH, AUTH, SELECT and their replies); it is not a general-purpose Redis client. It does not (yet) implement the adapter's remote request/response features such as cross-node fetchSockets or server-side acknowledgements.

Index

Examples

Constants

View Source
const MaxArrayLength = 1 << 20

MaxArrayLength bounds the declared element count of a RESP array ("*<n>"), for the same reason as MaxBulkLength: the count is used to size a slice before any element has been read. Redis pub/sub replies have three elements.

View Source
const MaxBulkLength = 64 << 20

MaxBulkLength bounds the declared length of a RESP bulk string ("$<n>") that readReply will accept. The length arrives on the wire before the bytes do, so without a bound a corrupt or hostile peer could make the client allocate an arbitrary amount of memory (or panic in make) from a handful of bytes. 64 MiB is far above any broadcast payload this adapter produces.

Variables

View Source
var ErrClosed = errors.New("redis: broadcaster closed")

ErrClosed is returned by Publish once the Broadcaster has been closed. The caller (socketio's broadcast operator) treats a Publish failure as "the cluster link is unavailable" and falls back to local-only delivery, so a closed or broken Redis link degrades instead of silently dropping messages.

View Source
var ErrReplyTooLarge = errors.New("redis: reply exceeds size limit")

ErrReplyTooLarge is returned when a RESP reply declares a bulk string or array larger than MaxBulkLength / MaxArrayLength, or nests deeper than the internal depth limit. It signals a corrupt or hostile peer, not a transient failure: the connection's framing can no longer be trusted.

Functions

This section is empty.

Types

type Broadcaster

type Broadcaster struct {
	// contains filtered or unexported fields
}

Broadcaster relays socketio broadcasts over Redis pub/sub. It satisfies socketio.Broadcaster.

func New

func New(opts Options) (*Broadcaster, error)

New connects to Redis, subscribes to the broadcast channel, and returns a Broadcaster ready to install with server.SetBroadcaster.

Example

ExampleNew shows how to turn a single-node Socket.IO server into a cluster member. It calls New to connect to Redis and subscribe to a shared pub/sub channel, returning a *Broadcaster that satisfies socketio.Broadcaster; the deferred Close tears the connections down on exit. It then creates a socketio.Server and installs the broadcaster with SetBroadcaster, after which every broadcast — here io.To("room1").Emit — is published once to Redis and delivered to the matching local sockets of every node subscribed to the same channel, including this one. Run this same code on each instance behind your load balancer and a message emitted on any node reaches clients connected to all of them. The reader should take away the three-line scale-out recipe: redis.New, SetBroadcaster, then broadcast as usual. (The example is compiled to verify the API but not executed here, as it needs a running Redis server.)

package main

import (
	"log"

	socketio "github.com/malcolmston/socketio"
	"github.com/malcolmston/socketio/redis"
)

func main() {
	bc, err := redis.New(redis.Options{
		Addr:    "localhost:6379",
		Channel: "socket.io",
	})
	if err != nil {
		log.Fatal(err)
	}
	defer bc.Close()

	io := socketio.New()
	io.SetBroadcaster(bc)

	// Fans out across every node subscribed to the "socket.io" channel.
	io.To("room1").Emit("news", "hello cluster")
}

func (*Broadcaster) Close

func (b *Broadcaster) Close() error

Close implements socketio.Broadcaster.

func (*Broadcaster) OnMessage

func (b *Broadcaster) OnMessage(fn func([]byte))

OnMessage implements socketio.Broadcaster.

func (*Broadcaster) Publish

func (b *Broadcaster) Publish(data []byte) error

Publish implements socketio.Broadcaster: it PUBLISHes data to the channel. It returns ErrClosed after Close, and the underlying I/O error if the Redis connection has failed.

type Options

type Options struct {
	// Addr is the Redis server address (host:port).
	Addr string
	// Channel is the pub/sub channel used for broadcasts (default "socket.io").
	Channel string
	// Password, if set, authenticates via AUTH.
	Password string
	// DB selects a Redis database via SELECT (default 0).
	DB int
	// Dial overrides the network dialer (used in tests).
	Dial func(addr string) (net.Conn, error)
}

Options configures the Redis broadcaster.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL