NATS
Это содержимое пока не доступно на вашем языке.
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 } from 'actor-ts';import { NatsActor, NatsOptions } from 'actor-ts/io';
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 tls?: TlsTransportOptionsType; // cert material; also enables TLS; code-only}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.
NATS has no tls:// URL scheme, so withTls does both jobs here: it
asks nats.js to negotiate TLS and says what the handshake should
trust. mTLS is the common production posture:
const natsOptions = NatsOptions.create() .withServers(['nats://nats.example.com:4222']) .withTls({ ca: fs.readFileSync('./tls/ca.crt', 'utf8'), cert: fs.readFileSync('./tls/client.crt', 'utf8'), key: fs.readFileSync('./tls/client.key', 'utf8'), });new NatsActor(natsOptions);Every field carries the material itself, never a path to it,
which is why the example reads the files. cert and key only
mean anything together, and one without the other is rejected when
the actor starts. Omit withTls entirely and the connection is
plaintext unless the server forces TLS, in which case nats.js
verifies it against the system trust store.
JetStreamActor takes the identical option. Neither has a config
key on purpose: a private key does not belong in application.conf.
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/io';
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.
