Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

laravel-event-sourcing v3 has been released

Original – by Freek Van der Herten – 3 minute read

Our spatie/laravel-event-sourcing package is probably the best starting point for event sourcing in Laravel. It has excellent docs, that explain event sourcing from scratch, support for aggregates, projectors, and much more! It's all beautifully integrated in Laravel.

Recently we released v3 of the package. In this blogpost I'd like to walk you through the changes.

This post will probably not make much sense to you if you don't know anything about event sourcing. To get up to speed, watch this introduction video first.

Improve performance by using snapshots

When an aggregate gets instantiate all events concerning that aggregate will be replayed on it first, so it has the right, current state. Typically, retrieving past events and replaying them is very fast, but if your aggregate needs a very large number of events to be replayed, this might take some time.

To solve this problem, we added snapshots to the package. A snapshot hold the state that an aggregate should have after a certain number of events have been replayed. By loading the aggregate you don't have to replay previous events anymore, and this improves performance.

You can create a new snapshot by calling the ->snapshot() method on your Aggregate.

$myAggregate = MyAggregate::retrieve($uuid);

$myAggregate->snapshot();

This will create a new snapshot in the snapshots table. By default we store the values of all the private, protected and public properties on the aggregate at that point in time. This is the default implementation of the getState method that gets all those properties.

protected function getState(): array
{
    $class = new ReflectionClass($this);

    return collect($class->getProperties())
        ->mapWithKeys(function (ReflectionProperty $property) {
            return [$property->getName() => $this->{$property->getName()}];
        })->toArray();
}

If you don't want all those properties in your snapshot, just override the getState() and useState() methods on the aggregate and implement your own behaviour.

When you retrieve the aggregate the next time, it will find the snapshot, set its internal properties back to what they were at the time of the snapshot, and apply any new events starting from the snapshot.

This uses the snapshots aggregateVersion, this version number is incremented each time an event is applied by the aggregate and stored in the snapshot.

This feature was added by Rias who did a great job!

Better protection against concurrency

To make snapshots work, we introduced the concept of a version. The version of an aggregate will increment for each events that was saved. This version will also protected your aggregate against concurrent persists. This can happen when there are two concurrent requests that try to update the same aggregate.

When reconstituting an aggregate from previous events the aggregate will remember the highest version id for that aggregate. If that highest version id differs differs from the highest one that the aggregate remembers, an exception will be thrown.

If concurrent persists should be allowed, you can set the $allowConcurrency static property on the aggregate to true.

use Spatie\EventSourcing\AggregateRoot;

class AggregateRootThatAllowsConcurrency extends AggregateRoot
{
    protected static bool $allowConcurrency = true;
}

This feature was suggested by Dries Vints.

In closing

I'm pretty happy with how the snapshot feature turned out, a lot of the users of the package were asking for this and I think we deliver a good, elegant solution.

To know more about the package, head over to the extensive documentation.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

What are your thoughts on "laravel-event-sourcing v3 has been released"?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.