Event Sourcing: Projections with Liquid Projections

Liquid Projections

Projections are an important yet pretty simple concept when working with event-centric or event sourcing systems. The concept is to build a state from a stream of events. In my previous post, Event Sourcing with SQL Stream Store, I made a pretty basic projection to keep the current account balance. In this post, I’ll use Liquid Projections to accomplish the same task.

I recommend checking out my post on SQL Stream Store as I’m using the same example/demo application in this post.

Liquid Projections

Liquid Projection is a library for building projections. The concept and API are pretty simple, and I’ll cover the basics in this post.

First I’ll update my Demo Application to use the Liquid Projections NuGet package.

Event Map

The first building block is creating an event map. The idea is to map an event to an action that we want to be invoked when the event occurs. We can use the EventMapBuild<TContext> to create all of our event mappings. The TContext can be anything but I’ll be using it to mutate the state that represents the current balance.

As a refresher from my previous post, here is the Balance

Now using the EventMapBuilder<Balance> to handle the Deposited and Withdrawn events.

You’ll notice call Build() on the EventMapBuilder<Balance> which will return us the EventMap<Balance>. At this point, you can call Handle() to pass in the events incoming from our subscription with our current Balance.

Conditions

There are also some nice additions such as providing conditions for when to execute a map. For example, if you wanted to handle only deposited events where the amount was greater than 100.

Inheritance

There is also support for inheritance, which means since my Deposited and Withdrawn events inherit from the AccountEvent base class, I could also have done

Event Store Integration

The next on my list is write this up directly with to something like Event Store or SQL Stream Store. Stay tuned.

Check out Liquid Projections on GitHub for more.

All the source code shown in this post is available on GitHub.

If you’d like a more detailed contented related to various aspects of event sourcing, let me know in the comments or on twitter.

Related Links:

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Event Sourcing with SQL Stream Store

Event Sourcing with SQL Stream Store

I’ve known about SQL Stream Store for a bit (I believe when it was called Cedar) but haven’t really looked into it much. The premise is to provide a stream store over SQL. Currently supporting MS SQL Server, PostgreSQL, and MySQL. Meaning it is simply a .NET Library you can use with an SQL implementation. Let’s take a look at how you can implement Event Sourcing with SQL Stream Store.

SQL Stream Store Demo Application

For this demo/sample, I’m going to create a .NET Core 3 console app. The idea will be to create the stereotypical event-sourcing example of a bank account.

I wanted to explore the primary functions needed of an event stream.

  • Create a Stream
  • Append a new Event to a Stream
  • Read Events from a Stream
  • Subscribe to a Stream to receive appended Events

NuGet Package

As always, the first thing is to get the SqlStreamStore NuGet Package by adding it as a PackageReference in your csproj.

I’ve also included Newtonsoft.Json because I’m going to be (de)serializing events.

Events

I’m going to create two events to represent the bank account transactions. Deposited and Withdrawn. Both of these will extend the abstract AccountEvent that will contain the TransactionId, Dollar Amount, and DateTime of the event.

Creating a Stream

There is no way of creating an empty stream. This is actually really nice. Instead when appending an event to a stream, if the stream does not already exist, it’s created. This is the same how EventStore works and should also feel familiar in comparison to the API.

Appending to a Stream

Appending a new event to a stream is pretty straight forward. From the IStreamStore there is an AppendToStream method that takes a few args.

The first is StreamId. This generally would represent your aggregate root ID. In this demo, I’m setting it Account:{GUID}.

The second arg is ExpectedVersion. This is also similar to the EventStore API. This is used for handling concurrency. You can specify an integer that represents the number of events that are persisted in the stream. You can also use the ExpectedVersion enum that can specify Any to not concern yourself with concurrency or NoStream to verify its the first event.

Finally, the 3rd param is an instance of NewStreamMessage. It contains the MessageId (GUID), an event name and the event json body.

An interesting takeaway here is the event name is intentionally made as a string so you are not serializing/deserializing to the CRL type name. This is a great idea since the CLR type name is likely to be changed more than just a plain string which you can keep constant.

Reading a Stream

You can read a stream forward or backward. Forward meaning from the very first event until the last, which is what I’ll use in this example.

You simply specify the StreamId, the starting version (0) and how many events to pull from the stream. The result contains an IsEnd to indicate there are no more events left in the stream to read.

Subscribing to a Stream

Subscribing to a stream is pretty straight forward. Specify the StreamId, the starting version/position of where you want to be notified of new events from, and then StreamMessageReceived for handling the newly appended event.

Wrapping it up

Now that I’ve covered all the primary aspects, it’s just a matter of adding some input/output to our console app by allowing the user to deposit and withdrawal from the account.

In the demo, I’m using the InMemoryStreamStore so there is no persisted data upon restarting the app. I’m also using a new GUID to represent the AccountId on each run.

Source Code

All the source code shown in this post is available on GitHub.

This was a quick look at just a few of the APIs in SQL Stream Store but should give you a feel for how it works.

If you’d like a more detailed contented related to various aspects of event sourcing, let me know in the comments or on twitter.

https://github.com/dcomartin/SqlStreamStore.Demo

Related Links:

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

EventStore for Orleans Grain Persistence

EventStore for Orleans Grain PersistenceIn my previous post, I used the JournaledGrain to create an Event Sourced grain.  This enabled us to raise events from within our grain which would be applied to our grain state.  Next up, which I’m covering in this post is how to use EventStore for Orleans Grain Persistence. This means when we raise events, they will also be persisted to EventStore.  When our grain is activated, we can re-hydrate it by retrieving prior events from an EventStore stream and re-running them in our Grain to get back to current state.

Blog Post Series:

EventStore

If you are unfamiliar with EventStore:
The open-source, functional database with Complex Event Processing in JavaScript.
If you don’t have a running instance, the easiest way is probably with Docker.  Pull down the latest image from docker hub and  as single node running. docker pull eventstore/eventstore docker run –name eventstore-node -it -p 2113:2113 -p 1113:1113 eventstore/eventstore There is a .NETStandard 2.0 compatible client package that I will be using in our Grain Project. Install-Package EventStore.ClientAPI.NetCore

Writing to EventStore

Anytime our grain was calling the JournaledGrain.RaiseEvent, we want to actually persist that to an EventStore Stream.  For my demo, we will have one EventStore stream per instance of an Orleans grain.  Meaning each bank account will have one event stream. I’m going to create a new RaiseEvent method that will call the base.RaiseEvent and once confirmed they were applied, append them to our EventStore Stream.  The additional private static methods are really just helpers for (de)serializing our events from/to json.

Re-hydrating

When our Grain activates with OnActivateAsync, this is when we will fetch all the events from our event stream and apply them to our grain.  Basically this will be replaying all the events to build our grain state back up to current state.
 

More!

If you want to try the demo, all the source is available on my PracticalOrleans GitHub Repo. Do you have any questions or comments? Are you using Orleans or EventStore?  I’d love to hear about it in the comments or on Twitter.

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.