slang

nats

Package nats.

Markdown version · llms.txt · api.json

A client for NATS: publish, subscribe (plain and queue groups), headers, request/reply, flush and drain, keepalive, and automatic reconnection with resubscription. It covers core NATS, not JetStream.

import "nats";

let r = nats.connect("nats://127.0.0.1:4222", deadline);
guard let nc = r else let e = err_of(r) { panic(e); }

let sr = nats.subscribe(nc, "orders.*");                  // or queue_subscribe(nc, subj, "workers")
guard let sub = sr else let e = err_of(sr) { panic(e); }
nats.publish(nc, "orders.new", b"{\"id\":1}");
let m = nats.next_msg(sub, deadline);                     // result[opt[Msg], str]: none at the deadline

let h: map[str][str] = {};
h["Trace-Id"] = ["abc"];
nats.publish_headers(nc, "audit", h, body);

let reply = nats.request(nc, "pricing.quote", b"BTC", deadline);   // result[Msg, str]
nats.respond(nc, request_msg, b"42");
nats.drain(nc, deadline);                                 // unsubscribe, let in-flight arrive, close

URLs are nats://host:port or tls://host:port, optionally with user:pass@ or token@. options(url) gives an Options to adjust before connect_with:

  • Servers and identity: servers (tried in turn), name.
  • Authentication: user/pass, token, nkey_seed, or a user JWT and seed via with_creds(o, creds_file_text). NKeys sign the server's nonce with Ed25519.
  • TLS: tls, ca_path, and tls_first for servers with handshake_first. By default INFO arrives in clear and the client upgrades before sending CONNECT, so credentials travel only over TLS.
  • Delivery and keepalive: pending (see below), ping_interval, max_pings_out.
  • Reconnection: reconnect, max_reconnects, reconnect_wait, reconnect_buffer.

One connection, one reader. A reader task parses what the server sends and hands each message to its subscription's channel, so next_msg parks rather than polls. A subscriber that falls more than pending (default 1,024) messages behind loses the newest ones and counts them in sub.dropped, rather than stalling every other subscription. This is the NATS "slow consumer" rule.

Deadlines. Each connection has one timer task that is parked while nothing waits on a deadline; deadlines resolve to within 10 ms.

Writes coalesce. Publishes append to one buffer, and a flusher task writes it out after a short wait (20 µs, or 200 µs while a publisher is streaming). A publisher that fills 32 KB first writes it itself.

Reconnection. When the connection breaks, or the server stops answering pings, the reader redials the servers in turn with jittered backoff, sends CONNECT and every live SUB again, then replays what was published in the meantime, up to reconnect_buffer (8 MiB). Delivery is at most once, as in core NATS: a message written into a connection just as it broke is lost. reconnects(nc), is_connected(nc) and last_error(nc) report the state.

request uses one shared inbox subscription for every request on the connection. If no subscriber is listening, the server's "no responders" status makes it fail at once rather than at its deadline. A -ERR 'Permissions Violation' leaves the connection up; any other -ERR or a malformed frame drops and redials it. Subjects are validated (no whitespace, no empty tokens, no wildcards in a publish), and header names and values are refused if they would inject protocol lines.

API#

gc struct Options stdlib/nats/nats.sl:36#
fn options(url: str) -> Options stdlib/nats/nats.sl:60#

Defaults for one server URL: nats://host:port, tls://host:port (TLS from the first byte) or nats://user:pass@host:port / nats://token@host.

fn with_creds(o: Options, creds_text: str) -> result[Options, str] stdlib/nats/nats.sl:83#

Options with the user JWT and nkey seed of a .creds file.

gc struct Msg stdlib/nats/nats.sl:102#
gc struct Sub stdlib/nats/nats.sl:111#
gc struct Conn stdlib/nats/nats.sl:138#
fn connect(url: str, deadline: until) -> result[Conn, str] stdlib/nats/nats.sl:179#

Connect to url (see options).

fn connect_with(o: Options, deadline: until) -> result[Conn, str] stdlib/nats/nats.sl:183#
fn publish(nc: Conn, subject: str, data: bytes) -> result[bool, str] stdlib/nats/nats.sl:1061#
fn publish_reply(nc: Conn, subject: str, reply: str, data: bytes) -> result[bool, str] stdlib/nats/nats.sl:1065#
fn publish_headers(nc: Conn, subject: str, headers: map[str][str], data: bytes) -> result[bool, str] stdlib/nats/nats.sl:1070#

Publish with headers (each key may carry several values).

fn publish_full(nc: Conn, subject: str, reply: str, headers: map[str][str], data: bytes) -> result[bool, str] stdlib/nats/nats.sl:1075#
fn subscribe(nc: Conn, subject: str) -> result[Sub, str] stdlib/nats/nats.sl:1187#
fn queue_subscribe(nc: Conn, subject: str, queue: str) -> result[Sub, str] stdlib/nats/nats.sl:1192#

Members of one queue group share the messages: each goes to one of them.

fn next_msg(sub: Sub, deadline: until) -> result[opt[Msg], str] stdlib/nats/nats.sl:1223#

The next message, waiting until deadline: none when the deadline passes or the subscription has ended (unsubscribed, max reached, connection closed).

fn unsubscribe(sub: Sub) -> result[bool, str] stdlib/nats/nats.sl:1246#
fn auto_unsubscribe(sub: Sub, max: int) -> result[bool, str] stdlib/nats/nats.sl:1257#

End the subscription by itself after max more messages.

fn request(nc: Conn, subject: str, data: bytes, deadline: until) -> result[Msg, str] stdlib/nats/nats.sl:1270#

Publish data to subject with a fresh reply subject and wait for the first reply. "no responders" (status 503, when nothing listens) is an error at once instead of a timeout.

fn request_headers(nc: Conn, subject: str, headers: map[str][str], data: bytes, deadline: until) -> result[Msg, str] stdlib/nats/nats.sl:1274#
fn respond(nc: Conn, req: Msg, data: bytes) -> result[bool, str] stdlib/nats/nats.sl:1320#

Reply to a request message.

fn flush(nc: Conn, deadline: until) -> result[bool, str] stdlib/nats/nats.sl:1331#

Wait until the server has processed everything sent so far (a PING round trip).

fn drain(nc: Conn, deadline: until) -> result[bool, str] stdlib/nats/nats.sl:1354#

Unsubscribe everything, let what is in flight arrive, then close.

fn close(nc: Conn) stdlib/nats/nats.sl:1377#
fn last_error(nc: Conn) -> str stdlib/nats/nats.sl:1422#

Why the connection is closed or last broke ("" while healthy).

fn is_connected(nc: Conn) -> bool stdlib/nats/nats.sl:1426#
fn reconnects(nc: Conn) -> int stdlib/nats/nats.sl:1430#
fn nkey_seed_raw(seed: str) -> result[bytes, str] stdlib/nats/nkeys.sl:114#

The 32-byte Ed25519 seed inside a user seed ("SU...").

fn nkey_public(seed: str) -> result[str, str] stdlib/nats/nkeys.sl:135#

The public key ("U...") for a user seed.

fn nkey_encode_seed(raw: bytes) -> result[str, str] stdlib/nats/nkeys.sl:146#

A user seed ("SU...") for a 32-byte Ed25519 seed: for tests and tools.

fn nkey_sign_nonce(seed: str, nonce: str) -> result[str, str] stdlib/nats/nkeys.sl:157#

The base64url signature of a server nonce, for CONNECT's "sig".

fn parse_creds(text: str) -> result[[str], str] stdlib/nats/nkeys.sl:166#

The user JWT and the seed from a .creds file (two armoured blocks).