Why module events share one stream, checked against the server
Storage is not a property of a subject — a stream is a separate object that covers one — so the question is always how many streams, not which topics are durable. Three facts decide it, two of them verified rather than assumed: NATS refuses overlapping streams instead of merging them, so a shared stream plus a per-module one is not available at all; a filter cannot express an exception; and a stream per module turns one cross-module consumer into one per module. So one stream, with per-subject caps for the fairness that matters. Per-module age is genuinely unavailable, and a module that needs it declares a seat.
This commit is contained in:
@@ -103,6 +103,28 @@ seat: telegram-sender
|
|||||||
If each consumer could tune it, the mesh's durability would be an emergent property of whichever
|
If each consumer could tune it, the mesh's durability would be an emergent property of whichever
|
||||||
manifest was edited last.
|
manifest was edited last.
|
||||||
|
|
||||||
|
**Why a module's own events do not carry their own retention, though the same rule would allow
|
||||||
|
it.** A seat owns its namespace and gets a stream of its own, so it can say. A module's events
|
||||||
|
share one `EVENTS` stream, and three facts about JetStream decide that they must:
|
||||||
|
|
||||||
|
- **Storage is not a property of a subject.** A subject is only an address; a *stream* is a
|
||||||
|
separate object that captures subjects matching a filter. So "this topic is durable" is always
|
||||||
|
really "some stream covers it", and something has to create that stream.
|
||||||
|
- **Overlapping streams are refused, not merged.** Verified against the server: a per-module
|
||||||
|
stream beside a shared `mesh.mod.*.event.>` is rejected with *subjects overlap with an existing
|
||||||
|
stream*. So "one stream by default, its own for a module that wants different retention" is not
|
||||||
|
available — it is all of one or all of the other, and a filter cannot express an exception
|
||||||
|
either.
|
||||||
|
- **A stream per module breaks cross-module consumption.** An audit logger consuming every
|
||||||
|
module's events is one consumer on one stream today; with a stream each it becomes one consumer
|
||||||
|
per module, created and destroyed as modules come and go.
|
||||||
|
|
||||||
|
So: one stream, and **per-subject caps** for the fairness that actually matters — a noisy emitter
|
||||||
|
cannot evict a quiet one, which is verified (a cap of three, ten messages on one subject and one
|
||||||
|
on another, leaves four). What is genuinely unavailable is a different *age* per module, because
|
||||||
|
JetStream ages per stream and not per subject. A module that truly needs its own retention has a
|
||||||
|
way to say so: declare a seat, which owns its namespace and gets its own stream.
|
||||||
|
|
||||||
**Scope gives per-node workers without a new concept.** A module running on three nodes that each
|
**Scope gives per-node workers without a new concept.** A module running on three nodes that each
|
||||||
need their own queue declares a node-scoped seat: one holder per node, three queues, same
|
need their own queue declares a node-scoped seat: one holder per node, three queues, same
|
||||||
machinery. Mesh-scoped and node-scoped seats already exist; here they do the work of "one shared
|
machinery. Mesh-scoped and node-scoped seats already exist; here they do the work of "one shared
|
||||||
|
|||||||
Reference in New Issue
Block a user