Fork me on GitHub

Occurrent
Event Sourcing Utilities for the JVM

Based on the cloud events specification
  • Java
  • Kotlin
// Your domain is a pure function from past events to new events, with no dependency on Occurrent.
List<GameEvent> handle(List<GameEvent> history, GameCommand command) { ... }

// Occurrent's application service loads the stream, runs your function, and appends the new events under optimistic concurrency.
ApplicationService<GameEvent> applicationService = new GenericApplicationService<>(eventStore, cloudEventConverter);
applicationService.execute(gameId, history -> handle(history, command));
// Your domain is a pure function from past events to new events, with no dependency on Occurrent.
fun handle(history: List<GameEvent>, command: GameCommand): List<GameEvent> { ... }

// Occurrent's application service loads the stream, runs your function, and appends the new events under optimistic concurrency.
val applicationService = GenericApplicationService(eventStore, cloudEventConverter)
applicationService.execute(gameId) { history -> handle(history, command) }

Stream or DCB, the same event store and domain model

Both application services run against the same event store, a single store with stream and DCB capabilities. The decide and evolve are identical too. A DCB decider only adds the consistency boundary the command reads and the tags for the events it writes, so a rule can span more than one entity without a shared stream.

Stream

// One boundary per stream
val game = Decider.create(
    initialState, ::decide, ::evolve
)
applicationService.execute(gameId, command, game)

DCB

// A boundary per decision, across entities
val game = DcbDecider.create(
    initialState, ::decide, ::evolve,
    ::boundaryFor, ::tagsFor
)
dcbApplicationService.execute(command, game)

What is Occurrent?

Unintrusive

You should be able to design your domain model without any dependencies to Occurrent or any other library. Your domain model can be expressed with pure functions that returns events. Use Occurrent to store these events.

Simple

Pick only the libraries you need, no need for an all or nothing solution.

Control

You should be in control! Magic is kept to a minimum and data is stored in a standard format (cloud events). You are responsible for serializing/deserializing the cloud events "body" (data) yourself.

Composable

Use the Occurrent components as lego bricks to compose your own pipelines. Components are designed to be small so that you should be able to re-write them tailored to your own needs if required. Write your own problem/domain specific layer on-top of Occurrent.

Library

Designed to be used as a library and not a framework to the greatest extent possible.

Pragmatic

Need consistent projections? You can decide to write projections and events transactionally using tools you already know (such as Spring @Transactional)!

Interoperable

Cloud events is a CNCF specification for describing event data in a common way. CloudEvents seeks to dramatically simplify event declaration and delivery across services, platforms, and beyond!

Data Format

Since you know that events are stored as Cloud Events even in the database you can use the database to your advantage. For example you can create custom indexes used for fast and fully consistent domain queries directly on an event stream (or even multiple streams).