Ensure events are only published if data operations succeed:
awaitoutbox.publish(medicineAssignedEvent, async (session, db) => { // Business logic in same transaction awaitdb.collection('assignments').insertOne(assignment, { session }) }) // Either both succeed or both fail - no inconsistency possible
At-Least-Once Delivery
Hermes guarantees delivery via the publish callback:
// ❌ Throws: Event not acknowledged, will retry thrownewError('Broker unavailable') }
Idempotent Handlers
Since events may be delivered multiple times, handlers must be idempotent:
publish: async (event) => { // Check if already processed using event data consteventId = `${event.type}-${event.patientId}` if (awaitisProcessed(eventId)) { return// Safe to skip }
⚠️ Key Difference from PostgreSQL: MongoDB's oplog has limited retention (typically hours),
unlike PostgreSQL WAL which is retained until acknowledged. This means:
Slow consumers risk data loss - If consumer is down longer than oplog retention
Monitor oplog size - Check rs.printReplicationInfo() for retention window
Fast recovery required - Restart consumers quickly to avoid missing events
Architecture
Hermes MongoDB leverages MongoDB Change Streams:
Application publishes events to the outbox collection within transactions
Hermes MongoDB
Production-ready implementation of the Outbox Pattern for MongoDB using Change Streams.
Features
Installation
Quick Start
Key Concepts
Transactional Event Publishing
Ensure events are only published if data operations succeed:
At-Least-Once Delivery
Hermes guarantees delivery via the publish callback:
Idempotent Handlers
Since events may be delivered multiple times, handlers must be idempotent:
MongoDB Configuration
Change Streams require a MongoDB replica set:
Initialize replica set:
Important: Oplog vs WAL
⚠️ Key Difference from PostgreSQL: MongoDB's oplog has limited retention (typically hours), unlike PostgreSQL WAL which is retained until acknowledged. This means:
rs.printReplicationInfo()for retention windowArchitecture
Hermes MongoDB leverages MongoDB Change Streams:
publishcallback for each eventAdvanced Features
WithScope for Multiple Events
Batch multiple event publishes in a single transaction:
Horizontal Scaling with Partition Keys
Scale horizontally by partitioning events:
Best Practices
typediscriminatorLinks
See