⚙️ Install
If you work with PostgreSQL, then:
npm i @chassisjs/hermes @chassisjs/hermes-postgresqlIf you work with MongoDB, then:
npm i @chassisjs/hermes @chassisjs/hermes-mongodb💡 The easiest example for MongoDB
First, create an OutboxConsumer instance.
const outbox = createOutboxConsumer<Event1 | Event2>({
client,
client.db('hospital'),
publish: async (event) => await eventBus.publish(event),
})Remember, that the publish has to throw an error if the delivery to the message broker fails.
Then, you can use the instance to publish events along with a database operation:
await outbox.publish(event, async (session, db) => {
await db.collection('test').insertOne({ param: 1 }, { session })
})As you see, the event is passed to the outbox.publish. Hermes starts a new database session and passes it in the first callback's parameter which is the second parameter.
The changes made in the callback will be persistend along with the passed event.
The event will be sent as fast as the message broker is available.
Alternatively, you can also create a session by your own:
await client.withSession(async (session) => {
await session.withTransaction(async (session) => {
await outbox.publish(event1, session)
await outbox.publish(event2, session)
})
})Partitioning
By default, Hermes works on default partition.
If you want to scale out Hermes, then you can use multiple partition keys and run separate instances for each partition key.
Example can be running Hermes instances for tenants of your system. Then, each Hermes will be responsible for one tenant.
➡️ If you noticed a performance issue: Consider, if your application is not too big, dealing with too many messages. Maybe it's time for a redesign and try to split your application into smaller ones?
const outbox1 = createOutboxConsumer<Event1 | Event2>({
client,
client.db('hospital'),
partitionKey: 'tenant-1',
publish,
})
const outbox2 = createOutboxConsumer<Event1 | Event2>({
client,
client.db('hospital'),
partitionKey: 'tenant-2',
publish,
})🧹 Cleaning
By default, Hermes does the cleanup on SIGTERM and SIGINT unless shouldDisposeOnSigterm is seto to false, then you have to call outbox.stop by your own.
