makeitrein

makeitrein

What concurrency issues does using Event Sourcing expose me to?

Happy Saturday, Elixir Forum - I’m exploring the Commanded event sourcing library for a potential weekend project. A coworker of mine mentioned that a common concurrency issue in event sourcing is having command handlers write multiple events to a stream when only one written event is valid.

For example, two “close bank account” commands are fired off at the same time, and the handler processes both. Thus, the handler writes two “closed bank accounts” events to the event stream. Only one “closed bank accounts” event should have been written.

Our discussion made me realize that I might not know what I’m getting into when using Event Sourcing - are there other potential concurrency problems that should I be wary of? I see that Commanded has a section related to “Command dispatch consistency guarantee” - does strong consistency protect against common concurrency problems?

First Post! Switch mode

bottlenecked

bottlenecked

Hi, not sure how exactly Commanded is implementing aggregates, but I’d expect they are using processes- which means that barring some grievous design error (either on their part or yours) that should not be a situation you will ever find yourself in, since processes can only ever process one message at a time. So in your example even if two ‘close account’ commands reach your process, the second one should fail the validation because the first should have been fully processed (command → validation → domain event → apply → store and publish)* before ever the next message is consumed from the process’s inbox.

Having said that, be sure to understand the tradeoffs when going the ES way for some part of your system- unless you really need it, you may be trading too much development effort for benefits you’re not using

*I may be getting the order wrong because I’m not familiar with the Commanded’s flavor of ES

Most Liked

slashdotdash

slashdotdash

Commanded uses a GenServer process for each aggregate instance so that commands for the same bank account will be handled serially. As long as you guard against closing an already closed account in the command handler you will be fine.

One caveat is if you have multiple nodes hosting the application and you do not use distributed Erlang. In this scenario you could have two instances of the same bank account process running on two different nodes. If the same command was being processed concurrently on both nodes then they would attempt to write the same account closed event to the event store. To protect against this issue the event store uses optimistic concurrency when appending events to each stream. This ensures that the first write will succeed and the second write will be rejected since there is a new event in the stream. Commanded will apply the new event to the aggregate and retry the command which will now fail since the account has already been closed. You could also include the current version of the aggregate in every dispatched command and have it be rejected if the aggregate’s actual version when processing the command doesn’t match.

GDPR compliance with regards to PII (personally identifiable information) data can usually be solved in one of three different ways in an event sourced system:

  1. “Crypto-shredding” where PII data is encrypted in events and the encryption key is thrown away to prevent read access to the data.
  2. Store PII in a separate mutable data store which allows modification and deletion.
  3. Allow events and/or streams to be modified (so not an immutable event store).

See [Recipe] GDPR compliance · Issue #4 · commanded/recipes · GitHub

slashdotdash

slashdotdash

Building an application which is fully event sourced is usually a bad idea, unless your intention is to learn the concepts involved. Event sourcing comes with some trade-offs such as accepting eventual consistency and requires more investment in modelling your domain over a typical CRUD based application. Therefore it’s better to use event sourcing where it is well suited: temporal models, complex business rules, auditability, etc.

It’s perfectly acceptable to mix CRUD and event sourcing within an application, but I’d recommend using a single style within each context.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Command handlers dont get to write to the event stream, they aren’t allowed. Command handlers have to ask an aggregate to actually do the command, and those aggregates serialize commands, meaning they run just one at a time. If a particular event sourcing library can’t guarantee serialized command handling for an aggregate, then it is a seriously flawed library. To my knowledge, Commanded does all of the right things there.

This does of course mean you need to choose your aggregates wisely, and understand how to run operations that involve multiple aggregates. To use your example, a bank account is a fine choice of aggregate, and the aggregate’s job will be to ensure that things like double closes don’t happen. Where things get tricky is something like a transer, wherein you want to move some funds from one aggregate to another. This tends to push things in a “TransferRequested” “TransferAccepted” style event log, which I actually think is pretty solid.

I’m not sure that these are common. If a library says it’s doing event sourcing, but it doesn’t provide a way to do serialized event handling around specific topics or aggregates, I’m not really sure it’s doing event sourcing. Certainly not CQRS.

Where Next?

Trending in Questions Top

jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
silverdr
Using Phoenix.LiveView.TagEngine as an EEx.Engine is deprecated! To compile HEEx, use Phoenix.LiveView.TagEngine.compile/2 instead. Sta...
New
saveman71
Hello ! We want new/edit form pages to POST/PUT to their own URL rather than the resources REST defaults (post /things, put /things/:id)...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
michallepicki
I am using Oban and occasionally, shortly after a deployment, a handful of jobs can fail because of dependency on other parts of the syst...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New

We're in Beta

About us Mission Statement