Introduction
Concordance is an open source, opinionated framework
built on top of wasmCloud. With Concordance, you describe the various
elements of your event sourced system as WebAssembly components. These components are
standards-compliant, freestanding .wasm
files that are secure, fast, portable, and
language-independent.
Why do we Need Event Sourcing?
Building applications in wasmCloud involves creating "pure functional", stateless actors. These actors can interact with the outside world through an effect system that we call capability providers. By leveraging their stateless, tiny form factor, wasmCloud can scale out these actors across any number of disparate infrastructures from the edge to the cloud to your laptop, Raspberry Pi and back again.
This is an incredibly powerful programming paradigm that will likely change distributed application development as we know it. However, a lot of people have been asking us as well as the wasmCloud maintainers for a more intrinsically stateful approach to actors. When we dug into the details behind these requests, we found that most people wanted stateful actors because they wanted to build event sourced applications.
The topic of event sourcing is large enough for a book (in fact, wasmCloud creator Kevin Hoffman is writing an event sourcing book that will be available in the resources section once in beta). In the meantime, you can read through this introduction's summary of the core building blocks and then move onto the full developer's guide from there.
The vast realm of event sourcing patterns and practices can be defined by this single most important core rule: reality as defined by your application is derived by the deterministic execution of functions across an immutable log of events that occurred in the past.
Building Blocks
Event sourced applications are built on a foundation of a small number of core building blocks. Regardless of how complex or distributed your application, you will always compose applications from some combination of the following primitives:
Commands
A command is a request to perform work. These are imperatives that should be named as such, e.g.
WithdrawFunds
, AttackGoblin
, or ConsumeFuel
. The aggregate validates the commands and, if
everything is in order, will output 1 or more corresponding and correlated events.
Events
An event is an immutable record of something that occurred in the past. These are typically named as
past-tense verbs, e.g. FundsWithdrawn
or GoblinAttacked
or ShipConsumedFuel
. It takes a bit of
mental gymnastics to switch from the world of imperative programming to event sourced, but the
payoff can be huge.
Aggregates
An aggregate is, as the name implies, an entity whose state is derived by the aggregation or folding of a function across the event stream. The domain-driven design specific definition of an aggregate is similar in inspiration: a representation of a collection of entities.
Aggregate state is derived by applying the aggregate function to events in the stream. In some
applications this aggregate might be an in-memory object (as in OOP) that is loaded, derives its
state, performs a calculation, and is then discarded. In distributed systems at massive scale, that
kind of aggregate is problematic. As such, a Concordance aggregate is an actor that is supplied with
state and an event to produce new state (e.g. f(state, event) = state'
). Concordance deals with
the management of aggregate state and all developers need to worry about is writing a function that
produces new state by applying an event.
Additionally, aggregates validate incoming commands and optionally emit one or more events in
response. It is important to realize that even despite the seemingly impossible restrictions in
place, all "work" in an event sourced system is instigated by commands. Conceptually, this is a
function that might look like f(command, state) = [event1, ...]
.
It is subtle but important to remember that aggregates cannot modify their state while processing commands. The only way an aggregate can change state is through the processing of events, so in many applications you'll see a pattern where aggregates appear to "send themselves" events in order to mutate their state.
Stateless Event Handlers
A stateless event handler is simply any actor that does not have internal state (e.g. not an aggregate or process manager) that is interested in one or more events. All side effects performed by this actor must go through wasmCloud's secure capability system. As you'll see later in the developers' guide, these event handlers can be specialized to take on the role of notifiers or even gateways.
Projectors
A projector is a special type of stateless event handler. Projectors receive events and use the data on those events to build a read model. This read model is stored data that is specifically designed to service user queries and is often referred to as a "materialized view" in SQL database circles. For more information on the difference between a read model and a write model, look for references and guides pertaining to CQRS, or Command, Query Responsibility Separation.
For example, you might have a projector that builds a leaderboard based on the entire history of games within a multiplayer environment. This lets clients query the leaderboard in O(1) cost because instead of doing SQL joins at query time, we're anticipating client needs and pre-generating the data they're going to need. If we need to generate more or differently-shaped data, we can simply purge the projections and replay to generate new projections.
Process Managers
A process manager does as its name implies. It manages processes. The special thing about event-sourced process managers is that a process begins and completes (or fails) with the receipt of specific events. The process is pushed forward by the process manager through the emission of commands. Some terminology on the internet says that process managers are responsible for "long-running" processes. In our case, "long-running" refers to the plurality of events and not the passage of real-world time.
If it helps in conceptualization, you can think of a process manager as the inverse of an aggregate. Aggregates convert commands into events while process managers convert events into commands.
Concordance Capability Provider
The concordance capability provider is the machinery that makes all of this work. It manages long-term state of aggregates and process managers, performs dispatch to all interested parties, manages durable event storage and the use of work queues to dispatch commands. In short, all of the "hard parts" of event sourcing are, as much as possible, encapsulated within the operation of this provider.
You'll see more information about how to operate this capability provider in the operations guide.