lilydocs
HTTP APIWebSocketConsumer
Broadcasting3 min read

Client targets and results

Select recipients within a namespace, broadcast, and handle partial queue-admission results.

context.clients() broadcasts to existing server connections. Use the WebSocket client to open a new connection to another server. All client target selections stay within the controller namespace.

Select recipients#

Selection Recipients
caller() Calling connection
others() Connections in the same namespace except the caller
all() Connections in the same namespace
client(id) / clients(ids) Explicitly selected connections
room(name) / rooms(names) A room or union of rooms
principal(id) Active devices of a verified identity
.except(ids) Connections excluded from the selection

Recipients are deduplicated in a room union. An explicit connection ID in another namespace does not cross the boundary; it counts as missing in the local report. An empty explicit selection can be a successful no-op after message validation.

Send#

Broadcasting from an action
context.clients().others()
    .send("chat:received", input)
    .await
    .map_err(WebSocketActionError::internal)?;

Use this snippet inside an action in the chat namespace receiving serializable input. Rooms provides a complete controller with imports and DTOs. The Emit outcome goes only to the caller; broadcasting requires this explicit target path.

Read a receipt#

send_with_receipt or send_binary_with_receipt makes partial admission visible:

Receipt snippet
let receipt = context.clients().all()
    .send_with_receipt("chat:received", input).await?;
let local = receipt.local();
let accepted_by_all_local_targets = local.is_fully_delivered();

The caller's error type must carry ConnectionError or convert it into its own error type. Results in receipt.local() satisfy:

Flow
targeted = sent + backpressured + closed + missing

sent means acceptance by a local outbound queue. The implementation of is_fully_delivered() checks targeted == sent; do not infer peer delivery from its name. The backplane receipt reports separate publish acceptance; it provides neither a remote recipient count nor an ACK total.

Handle partial results#

The convenience .send() returns an error if all required acceptance conditions are not met. PartialBroadcast, Backpressure, BackplaneUnavailable { local }, and BackplanePublish { local, source } may include local effects that already occurred. DispatchInterrupted can have partial local effects without a completed report; backplane publication has not started yet.

Do not blindly retry these results; the same recipient may see the message twice. Build an idempotency or application-ACK model separately when needed. clients().count() counts only the namespace on this node, while app.active_connection_count() counts local connections for the entire app; closing connections count until removed from the registry.

Sources for this page v0.1.0

This guide is based on the reviewed framework commit.

QUICK START
Documentation
Source code