Event Bridges
Event bridges are the transport backbone of PURISTA. They determine routing, scaling behavior, durability options, and delivery guarantees.
Support matrix
| bridge | scale out | durable subscriptions | manual ack | event-to-queue strongest handoff | stream support (openStream) |
|---|---|---|---|---|---|
| Default | no | no | no | no, auto-ack in-memory fallback | yes |
| AMQP | yes | yes | yes | yes | no (currently) |
| MQTT | yes | broker-dependent | no | no, QoS-dependent delivery only | no (currently) |
| NATS | yes | yes with JetStream, no with core NATS | yes with JetStream, no with core NATS | yes with JetStream | no (currently) |
| Dapr | yes | component-dependent | component-dependent | component-dependent | no (currently) |
For event-to-queue bindings, PURISTA asks for durable/manual-ack subscription semantics when the active event bridge advertises both capabilities. If not, the binding remains API-compatible and uses the bridge's best available behavior. See Event-to-queue for the exact limitation.
Command reliability model
| bridge | command transport | timeout source | pending invocation cancellation on shutdown | response confirmation |
|---|---|---|---|---|
| Default | in-memory | PURISTA pending invocation timer | yes | none |
| AMQP | reply queue | PURISTA pending invocation timer + AMQP message expiration | yes | broker confirm |
| MQTT | topic correlation | PURISTA pending invocation timer + MQTT messageExpiryInterval | yes | protocol-level (QoS dependent) |
| NATS | request/reply | native NATS request timeout | no (request timeout owned by NATS request call) | protocol-level |
| Dapr | HTTP request | sidecar/client request timeout | no (request lifecycle owned by sidecar/client timeout) | protocol-level |
Subscription consumer failure handling
| bridge | bounded retry | delayed retry | dead-letter target | strict startup validation |
|---|---|---|---|---|
| Default | no | no | no | yes |
| AMQP | yes | yes, broker-managed delayed retry queue when retryDelayMs > 0 on durable subscriptions | yes | yes |
| MQTT | no | no | no | yes |
| NATS | yes with JetStream | yes with JetStream | yes with JetStream | yes |
| Dapr | component-dependent | component-dependent | component-dependent | yes |
Queue bridge support
| queue bridge package | preferred workloads | compatible event bridges |
|---|---|---|
@purista/core default queue bridge | local dev, unit tests, single instance deployments | Any (in-memory inside the service) |
@purista/redis-queue-bridge | production pull-based CQRS, delayed jobs, AI worker pools | Default, AMQP, MQTT, NATS, Dapr (redis acts as the queue backend while the event bridge handles command/subscription traffic) |
@purista/nats-queue-bridge | production pull-based workloads on NATS-first platforms | Default, AMQP, MQTT, NATS, Dapr (JetStream acts as the queue backend while the event bridge handles command/subscription traffic) |
Future queue bridge packages will live next to the event bridge adapters once those providers expose reliable pull + lease semantics. When evaluating infrastructure, pick an event bridge + queue bridge pair that matches your durability and scaling needs.
See the dedicated Queue Bridges page for wiring guidance and capability details.
Delivery semantics in practice
PURISTA itself provides typed message contracts and processing flow. Delivery guarantees come from the selected bridge + broker/component configuration.
at-most-once: low latency, but a message can be lost on failures.at-least-once: safer delivery, but duplicates are possible.exactly-once: generally not guaranteed end-to-end in distributed systems; design handlers to be idempotent.
Late command responses are normalized across invoke-capable bridges in this slice. Once the caller-side timeout fires, PURISTA keeps a short-lived tombstone for the correlation id and ignores any later response with a warning instead of raising a bridge error.
Subscription retry and dead-letter handling are capability-driven bridge concerns. Service definitions can declare consumer failure handling in strict or best-effort mode. In strict mode, PURISTA fails startup if the selected adapter cannot honor the requested semantics. Exhausted subscription messages are dead-lettered. Where adapter capabilities allow it, handlers can explicitly return drop and stop-consumer.
Command registrations now follow the same strict startup validation approach for delivery semantics. If a command requests durable/manual-ack handling that the active bridge cannot provide, startup fails early instead of silently degrading. Commands are treated as single request/response operations: they are not retried by subscription retry policies. Handler failures are returned as CommandErrorResponse (UnhandledError for unhandled failures) instead of triggering transport redelivery loops.
Reliability checklist
- configure broker durability/retry features explicitly
- check
eventBridge.capabilitiesbefore relying on durable/manual-ack event-to-queue handoff - keep bridge settings identical across instances
- implement idempotency in command/subscription side effects
- define timeout/retry policies intentionally (do not rely on defaults only)
- keep subscription retry budgets bounded and route poison messages to a dead-letter target
- verify shutdown, readiness, and reconnect semantics in integration tests
- test reconnect and broker outage scenarios in integration tests
When to use which bridge
DefaultEventBridge: local development, single-instance deployments, stream development.AMQP: production systems with durable queues/retries and strong operational control.MQTT: IoT/edge and broker setups where topic/QoS tuning is central.NATS: low-latency eventing where simple operations are preferred.NATSwith JetStream: good fit when you want bounded subscription retries and dead-letter subjects without introducing a separate queue backend.Dapr: polyglot/service-mesh environments leveraging Dapr components.
