121 lines
4.4 KiB
Markdown
121 lines
4.4 KiB
Markdown
Publish-Subscribe
|
|
|
|
Everything in NATS starts with publish-subscribe. A publisher sends a message to a subject, and every subscriber listening on that subject gets a copy. This is the foundation everything else builds on.
|
|
|
|
How It Works
|
|
|
|
1.Publishers send messages to a subject — a simple string like orders.created
|
|
2.Subscribers express interest in subjects they care about
|
|
3.NATS delivers a copy of each message to every matching subscriber
|
|
4.No coupling — publishers don't know about subscribers, and subscribers don't know about publishers
|
|
|
|
This decoupling gives you tremendous flexibility. Services can be added, removed, or restarted without coordinating with anyone else.
|
|
|
|
|
|
Publishing Messages
|
|
|
|
You publish a message by sending it to a subject:
|
|
|
|
#!/bin/bash
|
|
|
|
# Publish a message to the "weather.updates" subject
|
|
nats pub weather.updates "Temperature: 72°F"
|
|
|
|
Python:
|
|
|
|
# Publish a message to the subject "weather.updates"
|
|
await nc.publish("weather.updates", "Temperature: 72°F".encode())
|
|
|
|
|
|
Key points:
|
|
|
|
1.Publishers don't wait for acknowledgments (fire-and-forget)
|
|
2.Messages are delivered to all active subscribers
|
|
3.If no subscribers exist, the message is simply discarded
|
|
|
|
|
|
Subscribing to Subjects
|
|
|
|
Subscribers express interest in subjects to receive messages:
|
|
|
|
#!/bin/bash
|
|
|
|
# Subscribe to messages on the "weather.updates" subject
|
|
nats sub "weather.updates"
|
|
|
|
Python:
|
|
|
|
# Subscribe to 'weather.updates' synchronously
|
|
sub = await nc.subscribe("weather.updates")
|
|
|
|
# Process messages
|
|
while True:
|
|
try:
|
|
msg = await sub.next(timeout=1)
|
|
print(f"Received: {msg.data.decode()}")
|
|
except TimeoutError:
|
|
break
|
|
|
|
|
|
When to Use Pub/Sub
|
|
|
|
Publish-subscribe is ideal when multiple services need to react to the same event:
|
|
|
|
1.Event broadcasting — notify services about user signups, order placements, deployments
|
|
2.Data distribution — send updates to multiple dashboards or monitoring services
|
|
3.Fan-out notifications — alert all interested parties about state changes
|
|
4.Audit logging — multiple services independently log the same events
|
|
|
|
|
|
Real-world example
|
|
|
|
Imagine an e-commerce system where an order is placed. You publish a single event:
|
|
|
|
nats pub orders.created '{"orderId": "123", "total": 99.99}'
|
|
|
|
Multiple services subscribe and each reacts differently:
|
|
|
|
1.Inventory Service updates stock levels
|
|
2.Email Service sends a confirmation email
|
|
3.Analytics Service records metrics
|
|
4.Shipping Service prepares the shipment
|
|
|
|
One publish, four independent reactions — no coordination needed.
|
|
|
|
---
|
|
|
|
## The goldfish boundary (what this paper describes, precisely)
|
|
|
|
Everything above is *core NATS*: fire-and-forget, delivered to active
|
|
subscribers only, discarded if no one listens. No memory. We found this
|
|
the live way on 2026-11-06: `nats sub "dev.>"` caught `dev.test.hello`
|
|
while the terminal sat open, and the bus has no record of it since.
|
|
|
|
JetStream adds the memory: streams claim subjects, messages are stored,
|
|
durable consumers replay and each tracks its own position.
|
|
|
|
## Estate mapping (our reality, host-verified)
|
|
|
|
| Item | Value | Truth of record |
|
|
|------|-------|-----------------|
|
|
| Bus | `nats-dev.eachpath.local:30000` (VM 122) | [host record](../../eachpath.local/saturn.eachpath.local/vms/nats-dev.eachpath.local/nats-dev.eachpath.local.md) |
|
|
| Streams | `REGISTER` -> `nimmerverse.register.>` (durable), `CYCLE` -> `nimmerverse.cycle.>` (100k msgs) | host record, 2026-11-06 |
|
|
| Publisher hosts | aynee (nats-cli + nats-py 2.16.0 in nimmer-lib venv), nimmerworld-dev | both, 2026-11-06 |
|
|
| Core-mode example | `dev.test.hello` = "Hello Nimmerverse!": live delivery only, in NO stream | verified 2026-11-06 |
|
|
|
|
Note: the generic example `orders.created` has no stream here; on OUR
|
|
estate, subjects without a stream are transient by design. Our persistent
|
|
naming is `nimmerverse.*` under the two streams above.
|
|
|
|
## Drills (run on our estate, record answers in section 5 of the 101 paper)
|
|
|
|
1. Terminal A (nimmerworld-dev): `nats pub nimmerverse.cycle.hello "dafit was here"`
|
|
Terminal B (aynee): `nats sub "nimmerverse.cycle.*"` - watch the `*`
|
|
match exactly one token.
|
|
2. `nats stream info CYCLE` - the bus has now *counted* the message.
|
|
3. Kill both terminals, start a subscriber again: core-mode subject is
|
|
empty, stream subject replays its history. That contrast IS the lesson.
|
|
|
|
## Understand-check (ten words, said back before any primitive builds on this)
|
|
|
|
> dafit's version: (to be said back) |