NATS
Este conteúdo não está disponível em sua língua ainda.
NatsActor integrates with NATS — the lightweight pub/sub
broker. Core NATS is fire-and-forget without durability;
for durable streams, see the JetStream variant.
import { ActorSystem, NatsActor, NatsOptions } from 'actor-ts';
const natsOptions = NatsOptions.create() .withServers(['nats://nats-1:4222', 'nats://nats-2:4222']) .withName('my-app');const nats = system.spawn( () => new NatsActor( natsOptions, ), 'nats',);
// Subscribe (wildcards supported):nats.tell({ kind: 'subscribe', subject: 'events.>', target: eventHandler,});
// Publish:nats.tell({ kind: 'publish', publish: { subject: 'events.user.signup', payload: JSON.stringify(event), },});Settings
Section titled “Settings”interface NatsOptionsType extends BrokerCommonOptionsType { servers: string[] | string; name?: string; // client identifier user?: string; password?: string; token?: string; subscriptions?: { subject: string; target: ActorRef<NatsMessage> }[]; // wired up at connect time}Subscriptions and reconnects
Section titled “Subscriptions and reconnects”subscriptions and the runtime subscribe command feed the same
desired set, held by the
BrokerActor base rather
than by the connection. Practical consequences:
- Every subscription — configured or added at runtime — is re-established on the new connection after a reconnect.
- A
subscribesent while the actor is disconnected is applied on the next connect instead of being dropped. { kind: 'unsubscribe', subject }removes the subject for good: it does not come back on the next reconnect, even if it came fromsubscriptions.- Re-subscribing a live subject swaps its target — the previous subscription is dropped first, so exactly one actor receives it.
// Added at runtime; still there after the broker restarts.nats.tell({ kind: 'subscribe', subject: 'audit.>', target: auditor });// Point the same subject at a different actor.nats.tell({ kind: 'subscribe', subject: 'audit.>', target: newAuditor });// Gone for good.nats.tell({ kind: 'unsubscribe', subject: 'audit.>' });Note that this is about the subscription, not the messages: core NATS has no durability, so anything published during the outage is still gone (see the caution below).
Subjects (NATS topics)
Section titled “Subjects (NATS topics)”NATS uses .-delimited subjects:
events.user.signupevents.user.deleteorders.priority.placedmetrics.gauge.cpuSubjects are case-sensitive; per convention they’re lowercase + dot-separated.
Wildcards
Section titled “Wildcards”| Wildcard | Matches |
|---|---|
* | Exactly one token (matches user in events.user.signup). |
> | One or more tokens (matches user.signup in events.user.signup). |
'events.>' → events.user.signup, events.user.delete, events.order.placed'events.*.signup' → events.user.signup, events.admin.signup> can only appear as the last token.
Request / reply
Section titled “Request / reply”Core NATS models request/reply with a reply subject: the requester
publishes with a replyTo subject and listens on it; the responder
sends its answer there. There’s no dedicated request command — you
compose it from publish / subscribe and the replyTo field.
// Requester — listen on a private reply subject, then publish the// request with `replyTo` pointing at it:nats.tell({ kind: 'subscribe', subject: 'reply.balance.42', target: replyHandler });nats.tell({ kind: 'publish', publish: { subject: 'account.balance', payload: JSON.stringify({ accountId: '42' }), replyTo: 'reply.balance.42', // responder answers on this subject },});
// Responder — subscribe to the request subject, answer on `replyTo`:class BalanceService extends Actor<NatsMessage> { constructor(private readonly nats: ActorRef<NatsCommand>) { super(); } override onReceive(message: NatsMessage): void { if (!message.replyTo) return; this.nats.tell({ kind: 'publish', publish: { subject: message.replyTo, payload: JSON.stringify({ balance: 100 }), }, }); }}Inbound NatsMessages carry subject, payload (a Uint8Array), and
replyTo (an empty string when the publisher set none). This is the
“RPC over NATS” pattern — a few hundred microseconds round-trip on
localhost.
When to use NATS
Section titled “When to use NATS”Three primary use cases:
- High-throughput pub/sub without the operational complexity of Kafka.
- Microservices request/reply — synchronous calls between services via subjects.
- Lightweight event distribution — fire-and-forget notifications, metrics, log streams.
For durable streams (replay, history, ack semantics), see JetStream below. For cluster-internal pub/sub, DistributedPubSub is simpler.
JetStream
Section titled “JetStream”For NATS with durability, use JetStreamActor:
import { JetStreamActor, JetStreamOptions } from 'actor-ts';
const jetStreamOptions = JetStreamOptions.create() .withServers(['nats://nats-1:4222']) .withStream({ name: 'ORDERS', subjects: ['orders.>'], storage: 'file', maxAge: 86_400 * 7 * 1_000_000_000, // 7 days (maxAge is in nanoseconds) });const js = system.spawn( () => new JetStreamActor( jetStreamOptions, ), 'js',);JetStream layers:
- Stream — durable log, subjects → records.
- Consumer — read cursor; multiple consumers can read the same stream independently.
- Ack semantics — like AMQP, consumers ack each message.
Use JetStream when you need:
- Replay — consumers can rewind to any offset.
- Persistence — survives broker restart (file-backed storage).
- Ordered consumption per subject.
Kafka still beats JetStream for massive scale (billions of events / sec across hundreds of partitions). JetStream is the sweet spot for “less than Kafka, more than core NATS.”
Peer dependency
Section titled “Peer dependency”npm install nats# or: bun add natsThe nats package includes both core NATS and JetStream clients.
Where to next
Section titled “Where to next”- I/O overview — the bigger picture.
- BrokerActor base — the shared lifecycle.
- Kafka — heavier durable streaming.
- MQTT — IoT-focused alternative.
- DistributedPubSub — for in-cluster pub/sub.
