Transport Layer

Transport Tradeoffs

  LocalBus NATS Core JetStream
Delivery In-process Fire-and-forget At-least-once
Persistence None None Durable
Latency Lowest Low Medium
Ordering Per-handler None Per-consumer
Replay No No Yes
Scalability Single process Multi-pod Multi-pod
Use case Monolith Ephemeral events Critical events

LocalBus

  • In-process only
  • Async (Emit) or sync (EmitSync) dispatch
  • No delivery guarantees
  • Ideal for monoliths, local domain events, or CQRS read model projection

NATS Core

  • Fire-and-forget across pods
  • No persistence - if no subscriber is listening, the message is lost
  • Request/Reply pattern for synchronous queries
  • Lowest latency distributed option

JetStream

  • At-least-once delivery with ACK/NAK
  • Consumer-managed retries with backoff
  • Horizontal scalability via consumer groups
  • Replay support from any point in the stream

JetStream Error Handling

The JetStream bus classifies invoker errors to decide message acknowledgment:

  • Success or duplicate → ACK (message processed)
  • Circuit open → NAK with delay (wait for recovery)
  • Rate limited → NAK with delay (wait for window)
  • Other errors → NAK (immediate retry, bounded by MaxDeliver)
  • Decode failure → Term (malformed, never retry)

Design Decision

JetStream is used only for transport, never for business logic concerns like DLQ or retries. Those are handled by the invoker chain, keeping the transport layer thin and focused.


Back to top

Copyright © 2025 Isaque de Souza Barbosa. Distributed under the MIT License.