Skip to content

Broadcast

Gerasimos (Makis) Maropoulos edited this page May 28, 2026 · 8 revisions

When to use this page

  • You want to send a message to every connection on the server.
  • You want to send a message to a subset (a room, a namespace, or "every client except the sender").
  • You want to send a message to a specific connection by ID.

Neffos broadcasting is non-blocking by default: a slow client never holds up new connections or other broadcasts. This is a significant departure from naive "iterate the connection list under a lock" schemes.

The big picture

A client never talks directly to another client. All traffic goes through the server, so the server is the only broadcaster. Two layers of helpers:

API Use when
NSConn.Broadcast(...) / NSConn.BroadcastOthers(...) You are inside an event callback and have the NSConn. Most common.
Server.Broadcast(exceptSender, msgs...) You don't have an NSConn — for example, in an HTTP handler that fires a notification, or in a background goroutine.

Broadcasting from inside an event callback

The recommended path. The new helpers in NSConn (Broadcast and BroadcastOthers) replace the older c.Conn.Server().Broadcast(c, msg) chain:

neffos.Events{
    "chat": func(c *neffos.NSConn, msg neffos.Message) error {
        // Echo the message to everyone EXCEPT the sender.
        c.BroadcastOthers(msg)
        return nil
    },
}

Broadcast sends to everyone including the sender; BroadcastOthers excludes the current connection. Both are server-side only — calling them on a client-side NSConn panics with a nil-pointer dereference.

Broadcasting from outside an event (Server.Broadcast)

When you don't have an NSConn (background job, HTTP handler, signal handler), use Server.Broadcast:

// websocketServer := neffos.New(...)

websocketServer.Broadcast(nil, neffos.Message{
    Namespace: "default",
    Event:     "system.notice",
    Body:      []byte("scheduled maintenance in 5 minutes"),
})

The first parameter is the exceptSender. Pass nil to broadcast to everyone, or any value that satisfies fmt.Stringer:

  • *neffos.Conn (the sender's connection)
  • *neffos.NSConn (the sender's namespaced connection)
  • *neffos.Room (the sender's room)
  • neffos.Exclude("connection-id") if you only have the string ID

Targeting a specific connection (Message.To)

To send a message to one connection by ID, fill Message.To:

websocketServer.Broadcast(nil, neffos.Message{
    Namespace: "default",
    Event:     "notification",
    Body:      []byte("you've got mail"),
    To:        "user-42",
})

The Namespace and Room checks still apply: the target connection must be connected to the namespace (and joined to the room, if Room is set).

Targeting a room

Fill Message.Room to deliver to every connection joined to that room within the namespace:

websocketServer.Broadcast(nil, neffos.Message{
    Namespace: "default",
    Room:      "lobby",
    Event:     "chat",
    Body:      []byte("welcome!"),
})

When called from an event callback, the NSConn helpers stay shorter:

c.BroadcastOthers(neffos.Message{
    Room:  "lobby",
    Event: "chat",
    Body:  []byte("welcome!"),
})

(Namespace is filled automatically from the NSConn.)

Delivery semantics

  • At-most-once. If a connection's outbox is saturated or the connection is mid-close, that connection silently drops the message. There is no per-message ack. If you need delivery confirmation, use The ask method instead.
  • Non-blocking. Server.Broadcast returns immediately. Slow consumers never block accepts or other broadcasts.
  • Order is per-receiver, not global. Two Broadcast calls A then B will each arrive at each receiver in order A→B, but two receivers may see them at different times.

Ordering trade-off: Server.SyncBroadcaster

If you need strict ordering at the cost of throughput (no in-flight overlap), set Server.SyncBroadcaster = true before clients connect:

ws := neffos.New(upgrader, handler)
ws.SyncBroadcaster = true

When a StackExchange is configured (Redis / NATS) this flag is ignored — the backend already serializes order.

Running code on every connection (Server.Do)

Broadcast only sends messages. To run arbitrary code on every connection (close them, increment counters, gather state), use Server.Do:

// Force-disconnect everyone from the "default" namespace.
websocketServer.Do(func(c *neffos.Conn) {
    c.Namespace("default").Disconnect(context.Background())
}, false)

log.Printf("%d clients disconnected", websocketServer.GetTotalConnections())

Server.GetTotalConnections() is an atomic read and cheap.

Or to terminate every connection entirely:

websocketServer.Do(func(c *neffos.Conn) {
    c.Close()
}, false)

Important: Server.Do runs on the server's dispatch goroutine. Long work inside fn delays accepting new connections and processing disconnects. Pass async = true if you need fire-and-forget.

See also

Clone this wiki locally