GH-6 - More reference documentation.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
[[events]]
|
||||
:imagesdir: images
|
||||
= Working with Application Events
|
||||
|
||||
To keep application modules as decoupled as possible from each other, their primary means of interaction should be event publication and consumption.
|
||||
@@ -52,7 +53,7 @@ Note, how we use Spring's `ApplicationEventPublisher` to publish a domain event,
|
||||
As event publication happens synchronously by default, the transactional semantics of the overall arrangement stay the same as in the example above.
|
||||
Both for the good, as we get to a very simple consistency model (either both the status change of the order _and_ the inventory update succeed or none of them does), but also for the bad as more triggered related functionality will widen the transaction boundary and potentially cause the entire transaction to fail, even if the functionality that is causing the error is not crucial.
|
||||
|
||||
A different way of approaching this is by moving the event consumption to asynchronous handling at transaction commit and treat secondary functionaly exactly as that:
|
||||
A different way of approaching this is by moving the event consumption to asynchronous handling at transaction commit and treat secondary functionality exactly as that:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@@ -70,7 +71,49 @@ public class InventoryManagement {
|
||||
|
||||
This now effectively decouples the original transaction from the execution of the listener.
|
||||
While this avoids the expansion of the original business transaction, it also creates a risk: if the listener fails for whatever reason, the event publication is lost, unless each listener actually implements its own safety net.
|
||||
Even worse, that doesn't fully work, as the system might fail before the method is even invoked.
|
||||
Even worse, that doesn't even fully work, as the system might fail before the method is even invoked.
|
||||
|
||||
[[events.publication-registry]]
|
||||
== The Event Publication Registry
|
||||
|
||||
Spring Modulith ships with an event publication registry that hooks into the core event publication mechanism of Spring Framework.
|
||||
On event publication, it finds out about the transactional event listeners that will get the event delivered and writes entries for each of them into an event publication log as part of the original business transaction.
|
||||
On event publication, it finds out about the transactional event listeners that will get the event delivered and writes entries for each of them (dark blue) into an event publication log as part of the original business transaction.
|
||||
|
||||
.The transactional event listener arrangement before execution
|
||||
image::event-publication-registry-start.png[]
|
||||
|
||||
Each transactional event listener is wrapped into an aspect that marks that log entry as completed if the execution of the listener succeeds.
|
||||
In case the listener fails, the log entry stays untouched so that retry mechanisms can be deployed depending on the application's needs.
|
||||
By default, all incomplete event publications are resubmitted at application startup.
|
||||
|
||||
.The transactional event listener arrangement after execution
|
||||
image::event-publication-registry-end.png[]
|
||||
|
||||
[[events.publication-repositories]]
|
||||
== Event Publication Repositories
|
||||
|
||||
To actually write the event publication log, Spring Modulith exposes an `EventPublicationRepository` SPI and implementations for popular persistence technologies that support transactions, like JPA, JDBC and MongoDB.
|
||||
You select the persistence technology to be used by adding the corresponding JAR to your Spring Modulith application.
|
||||
We have prepared dedicated <<events.starters, starters>> to ease that task.
|
||||
|
||||
The JDBC-based implementation will create a dedicated table for the event publication log, unless a table with a particular name already exists.
|
||||
For details, please consult the <<appendix.schemas, schema overview>> in the appendix.
|
||||
|
||||
[[events.serialization]]
|
||||
== Event Serializer
|
||||
|
||||
Each log entry contains the original event in serialized form.
|
||||
The `EventSerializer` abstraction contained in `spring-modulith-events-core` allows plugging different strategies for how to turn the event instances into a format suitable for the datastore.
|
||||
Spring Modulith provides a Jackson based implementation through the `spring-modulith-events-jackson` artifact, which registers a `JacksonEventSerializer` consuming an `ObjectMapper` through standard Spring Boot auto-configuration by default.
|
||||
|
||||
[[events.starters]]
|
||||
== Spring Boot Event Registry Starters
|
||||
|
||||
Using the transactional event publication log requires a combination of artifacts added to your application.
|
||||
To ease that task, Spring Modulith provides starter POMs that are centered around the <<events.publication-repositories, persistence technology>> to be used and default to the Jackson-based `EventSerializer` implementation.
|
||||
The following starters are available:
|
||||
|
||||
* `spring-modulith-starter-jpa` -- Using JPA as persistence technology.
|
||||
* `spring-modulith-starter-jdbc` -- Using JDBC as persistence technology. Also works in JPA-based applications but bypasses your JPA provider for actual event persistence.
|
||||
* `spring-modulith-starter-mongodb` -- Using MongoDB behind Spring Data MongoDB.
|
||||
|
||||
|
||||
@@ -1,9 +1,49 @@
|
||||
[[moments]]
|
||||
= Moments -- a Passage of Time Events API
|
||||
|
||||
[[moments.subheadline]]
|
||||
== Subheadline
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
`modulith-moments` is a Passage of Time Events implementation heavily inspired by Matthias Verraes https://verraes.net/2019/05/patterns-for-decoupling-distsys-passage-of-time-event/[blog post].
|
||||
It's an event-based approach to time to trigger actions that are tied to a particular period of time having passed.
|
||||
|
||||
To use the abstraction, include the following dependency in your project:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.modulith</groupId>
|
||||
<artifactId>modulith-moments</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
The dependency added to the project's classpath causes the following things in your application:
|
||||
|
||||
* Application code can refer to `HourHasPassed`, `DayHasPassed`, `WeekHasPassed`, `MonthHasPassed`, `QuarterHasPassed`, `YearHasPassed` types in Spring event listeners to get notified if a certain amount of time has passed.
|
||||
* A bean of type `org.springframework.modulith.Moments` is available in the `ApplicationContext` that contains the logic to trigger these events.
|
||||
* If `spring.modulith.moments.enable-time-machine` is set to `true`, that instance will be a `org.springframework.modulith.TimeMachine` which allows to "shift" time and by that triggers all intermediate events, which is useful to integration test functionality that is triggered by the events.
|
||||
|
||||
By default, Moments uses a `Clock.systemUTC()` instance. To customize this, declare a bean of type `Clock`.
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@Configuration
|
||||
class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
Clock myCustomClock() {
|
||||
// Create a custom Clock here
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Moments exposes the following application properties for advanced customization:
|
||||
|
||||
.Available application properties
|
||||
[%header, cols="3,1,2"]
|
||||
|===
|
||||
|Property|Default value|Description
|
||||
|`spring.modulith.moments.enable-time-machine`|false|If set to `true`, the `Moments` instance will be a `TimeMachine`, that exposes API to shift time forward. Useful for integration tests that expect functionality triggered by the Passage of Time Events.
|
||||
|`spring.modulith.moments.granularity`|hours|The minimum granularity of events to be fired. Alternative value `days` to avoid hourly events.
|
||||
|`spring.modulith.moments.locale`|`Locale.getDefault()`|The `Locale` to use when determining week boundaries.
|
||||
|`spring.modulith.moments.quarter-start-month`|`Months.JANUARY`|The month at which quarters start.
|
||||
|`spring.modulith.moments.zone-id`|`ZoneOffset#UTC`|The `ZoneId` to determine times which are attached to the events published.
|
||||
|===
|
||||
|
||||
|
||||
BIN
src/docs/asciidoc/images/event-publication-registry-end.png
Normal file
BIN
src/docs/asciidoc/images/event-publication-registry-end.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 150 KiB |
BIN
src/docs/asciidoc/images/event-publication-registry-start.png
Normal file
BIN
src/docs/asciidoc/images/event-publication-registry-start.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
Reference in New Issue
Block a user