Welcome to EventSauce4j¶
eventsauce4j is a lightweight event sourcing toolkit for Java + Spring Framework, inspired by EventSauce (PHP).
It provides clean building blocks for domain events, message repositories, dispatching, outbox, with a persistence module.
If you know EventSauce in PHP, you should feel at home: the vocabulary, responsibilities, and flow are intentionally adapted to Java idioms.
Why EventSauce4j?¶
Event sourcing is a powerful architectural pattern, but many existing libraries are large, opinionated, or hard to integrate with.
The goals of eventsauce4j are:
- Minimal footprint, easy to embed in Spring / Spring Boot
- Pluggable persistence / transport / serialization
- A pragmatic event sourcing library for Spring framework with a focus on developer experience.
Modules¶
| Module | Description |
|---|---|
| eventsauce4j-core | Synchronous implementation of the message dispatcher and core event sourcing components. |
| eventsauce4j-jpa | JPA-based implementation of the Outbox pattern for reliable event persistence and publication. |
| eventsauce4j-rabbitmq | RabbitMQ producer and consumer support for inter-service event communication. |
| eventsauce4j-jackson | JSON event serialization and deserialization using Jackson. |
Core Concepts¶
This section introduces the fundamental building blocks of eventsauce4j and explains how they interact to support event-sourced applications in Java and Spring.
π¨ Message Decoration¶
EventSauce4j allows message decoration, meaning you can attach additional metadata (headers) to your messages. This is useful for adding contextual information before a message is persisted or dispatched, such as correlation IDs, tenant identifiers, or trace information.
β‘ Event Dispatcher¶
Events are a central concept in event sourcing, but theyβre also valuable beyond it. An event dispatcher decouples systems by propagating events to subscribers, enabling clean separation between write and read models or between microservices.
In eventsauce4j, the event dispatcher ensures that domain events flow seamlessly from your aggregates to handlers or external systems.
π§ Message Dispatcher¶
The message dispatcher is responsible for sending messages to registered MessageConsumers.
It defines how events are actually delivered synchronously or asynchronously depending on the module in use.
Custom Dispatchers
You can implement your own message dispatcher by implementing the MessageDispatcher interface.
π€ Inflector¶
An Inflector converts event class names into string identifiers when storing events. When reconstructing events, it performs the reverse: mapping the stored string back to the correct fully-qualified class name.
This mechanism supports cross-service communication and event versioning.
How It Works
The Inflector composes your event type mappings using several strategies:
- ExternalInflector β maps external event packages
- AnnotationInflector β maps annotated event classes
- StaticInflector β defines explicit key-to-class mappings
Example: Cross-Service Event Mapping
When dispatching a UserCreated event from user-service to payment-service via RabbitMqMessageDispatcher,
the consumer service must know how to deserialize it to its local event type.
You can define this mapping as follows:
new StaticInflector(Map.of(
"payment.public.userCreated", PaymentUserCreated.class
));
π§© Message Serializer¶
The message serializer is responsible for converting messages to and from serialized formats for persistence or transport. When implementing a custom message repository, youβll typically use this interface.
By default, eventsauce4j provides an jackson-based serializer, but you can easily implement your own strategy (e.g., JSON, Avro, Protobuf) to fit your infrastructure.
ποΈ Outbox¶
The Outbox pattern ensures that event persistence and dispatching occur atomically, either both succeed or both fail.
Why It Matters
Without an outbox, persisting domain changes and dispatching events involve two separate network operations. If one fails, inconsistencies can occur.
The transactional outbox buffers events in a dedicated database table before dispatching them asynchronously. Although this adds slight latency, it guarantees at-least-once delivery and ensures that only persisted events are published to consumers.
π Outbox Lock¶
In horizontally scaled Spring Boot applications (multiple instances of the same service), itβs crucial to prevent duplicate event consumption.
EventSauce4j uses an outbox lock mechanism so that only one instance at a time processes pending events from the outbox table. This ensures consistent, non-duplicated event delivery across your service cluster.
π Back-off Strategy¶
The Backoff Strategy in EventSauce4j is a mechanism used to handle temporary delivery failures when sending messages. It determines how the system should wait and retry after a failure, helping ensure reliable message delivery without overwhelming the system.
EventSauce4j provides two types of backoff strategies:
SimpleBackOffStrategy When a message delivery fails, this strategy retries a fixed number of times with a constant delay between attempts. If all retries fail, the message is moved to a Dead Letter Queue (DLQ) or Dead Letter Table for later inspection.
ExponentialBackOffStrategy In this approach, the delay between retries increases exponentially after each failed attempt. This means the system waits longer before each subsequent retry.
eventsauce4j:
backoff: simple #exponential
πΎ Commit Strategy¶
Messages can be committed using two strategies:
- Mark message as consumed
- Delete the message
eventsauce4j:
archive: true #false will delete the message