Broadcast channel
This subpackage gives notify its live-push channel: import it when a notification needs to reach connected clients immediately, on top of or instead of the database channel's durability.
import "github.com/gp-system/notify/broadcast"
Broadcast
notify/broadcast is the live-push side of a notification: a thin, Valkey-backed publisher built on centrifugal/centrifuge, the library behind Centrifugo and Grafana Live. It is deliberately small: publishing is fire-and-forget, and durability lives entirely in the database channel, not here. The package is shared between two roles: any process (typically the worker) imports it just to publish, while the dedicated realtime gateway also uses it to hold connections and relay what gets published; see that page for the gateway side (cmd/realtime, scaling, the client).
A notification opts into this channel through a third content interface, alongside Mailable and Databasable:
type Broadcastable interface {
ToBroadcast(ctx context.Context, r Recipient) (broadcast.Message, error)
}
ValkeyConfig
type ValkeyConfig struct {
Addr string
Password string
DB int
}
ValkeyConfig deliberately carries no env struct tags of its own: notify/broadcast is a library, not a place to own an env namespace. The realtime chassis builds one from its own VALKEY_*-tagged configuration and passes it in (realtime.Config.BroadcastValkey()); a non-chassis publisher does the same from whatever config it already has. See Realtime for the exact mapping.
Config
type Config struct {
ChannelPrefix string `env:"CHANNEL_PREFIX" envDefault:"rt"`
}
Unlike ValkeyConfig, Config does carry its own env tag (CHANNEL_PREFIX). The kit embeds it under its own REALTIME_ prefix, so in a generated project it surfaces as REALTIME_CHANNEL_PREFIX; see Realtime and the configuration reference for the full variable list. ChannelPrefix namespaces every Valkey channel this package touches, so multiple projects (or multiple environments) can share one Valkey instance without colliding.
Publishing
pub, err := broadcast.NewPublisher(ctx, valkeyCfg, cfg)
pub := broadcast.MustNewPublisher(ctx, valkeyCfg, cfg) // panics on error; the usual main() constructor
err := pub.Publish(ctx, channel, msg)
err = pub.Close()
Publisher is a publish-only centrifuge.Node sharing the project's Valkey broker; it never accepts a connection, so a process that only publishes (a worker, a one-shot script) depends on nothing but a network client to Valkey. Publish is fire-and-forget: a failed publish is returned to the caller, not retried and not queued, which is why the database channel is the durability story, not this one.
notify.NewBroadcastChannel(pub, cfg.ChannelPrefix)
wraps a Publisher into the notify.Channel the Hub dispatches Broadcastable content to.
Channel naming: UserChannel and TopicChannel
func UserChannel(prefix, subject string) string // a recipient's own channel
func TopicChannel(prefix, topic string) string // a shared, opt-in topic channel
Every connection the realtime gateway accepts is server-side subscribed to its own UserChannel, which is how a notification addressed to a Recipient.ID reaches exactly that user's live connection with no client-side subscribe call. TopicChannel names the shared channels used for broadcast beyond single-recipient notifications (announcements, admin alerts); see Realtime: shared topic channels for the TopicAuth/Allow/AllowPrefix authorization these require, which relies on auth/rbac's Identity.
NewNode
func NewNode(cfg ValkeyConfig, centrifugeCfg centrifuge.Config) (*centrifuge.Node, error)
NewNode is the shared constructor behind both roles: a publish-only node (what NewPublisher wraps) and the full connection-accepting node the realtime gateway runs. It wires the Valkey broker centrifuge needs to fan a publish out across every gateway instance, regardless of which process published it.
Memory
mem := broadcast.NewMemory()
pub := mem.All() // []broadcast.Published, everything captured so far
Memory is a test double: it captures every publish instead of touching Valkey, so a notification's ToBroadcast (or a channel wired with notify.NewBroadcastChannel(mem, prefix)) can be asserted on directly, the same way mail.NewMemory() and notifydatabase.NewMemoryStore() stand in for their real drivers.
With the kit
The gateway that turns a Publish call into a live client push, its scaling model, and the client-side subscription story are all on the Realtime page. The authorization model for shared topic channels builds on auth/rbac's Identity. Wiring the broadcast channel into a notification's Via is covered by add notification.