A Transactional Event Library that implements the outbox pattern for Jakarta EE 9.
The following APIs are required:
- CDI 3.0
- Concurrency Utilities 2.0
- JDBC 4.2
- JTA 2.0
The following APIs are optionally supported for serialization:
- JAXB 3.0
- JSON-B 2.0
An Event can be published using the EventPublisher
API:
@Inject
private EventPublisher publisher;
public void someMethod() {
...
SomeEvent event = ...
publisher.publish(event);
...
}
For every event type published there must be a corresponding Handler
(qualified by EventHandler
):
@Dependent
@EventHandler
class SomeEventHandler extends AbstractHandler<SomeEvent> {
@Override
protected void handle(SomeEvent event) {
...
}
}
With a CDI version greater or equal to 4.1 it is even possible to simply annotate any class bean method (not static and not private) with @EventHandler
.
The annotated method must have exactly one argument.
@Dependent
class SomeBean {
@EventHandler
void doIt(SomeEvent event) {
...
}
}
The library expects that the following table exists when using the javax.sql.DataSource
with the Events
qualifier:
CREATE TABLE event_store (
id VARCHAR(50) NOT NULL,
event_type VARCHAR(50) NOT NULL,
context VARCHAR(4000),
payload VARCHAR(4000) NOT NULL,
published_at TIMESTAMP NOT NULL,
tries INT NOT NULL,
lock_owner VARCHAR(50),
locked_until BIGINT NOT NULL,
PRIMARY KEY (id)
);
CREATE INDEX event_store_locked_until ON event_store (locked_until);
The required javax.sql.DataSource
can be specified like the following:
@Dependent
class EventsDataSource {
@Events
@Produces
@Resource(name = "someDb")
private DataSource dataSource;
}
The Quarkus Configuration is documented on the project site.
The configuration properties are the same without the quarkus.
prefix and camel case instead of kebab case if not running in Quarkus.
If mpMetrics is enabled on the server there will be the following metrics
- application_com_github_jonasrutishauser_transaction_event_published_total (number of published events)
- application_com_github_jonasrutishauser_transaction_event_failedattempts_total (these are the number of failed attempts to process an event)
- application_com_github_jonasrutishauser_transaction_event_success_total (these are the number of successfully processed events)
- application_com_github_jonasrutishauser_transaction_event_blocked_total (these are the number of blocked events because the maximum number of retries has been reached)
- application_com_github_jonasrutishauser_transaction_event_unblocked_total (these are the number of unblocked events)
- application_com_github_jonasrutishauser_transaction_event_deleted_total (these are the number of deleted events)
- application_com_github_jonasrutishauser_transaction_event_processing (the number of events being processed currently in total)
- application_com_github_jonasrutishauser_transaction_event_dispatched_processing (the number of dispatched events by a timer being processed currently. This metric can be used for fine-tuning transactional.event.maxConcurrentDispatching and transactional.event.maxAquire)
- application_com_github_jonasrutishauser_transaction_event_all_in_use_interval (interval between lookups for events to process when maxConcurrentDispatching is reached)
- application_com_github_jonasrutishauser_transaction_event_max_dispatch_interval (maximum interval between lookups for events to process)
- application_com_github_jonasrutishauser_transaction_event_initial_dispatch_interval (initial interval between lookups for events to process)
- application_com_github_jonasrutishauser_transaction_event_max_aquire (maximum number of events aquired per query)
- application_com_github_jonasrutishauser_transaction_event_max_concurrent_dispatching (maximum number of dispatched events being processed concurrently)
- application_com_github_jonasrutishauser_transaction_event_dispatch_interval (interval between lookups for events to process)