looplab / eventhorizon

Event Sourcing for Go!
Apache License 2.0
1.57k stars 196 forks source link

Sort events before applying them to aggregate #411

Open totemcaf opened 11 months ago

totemcaf commented 11 months ago

Description

When an aggregate is materialized, events are read from the event source. In the case of the MongoDB implementation, the way they are read does not guarrants the event order.

This change sort events before applying them.

Affected Components

Related Issues

409

Solution and Design

Events are sorted by version number before being applied. Because version number is an integer between A and B, being A the first version read, and B the last, the sort uses the version position to insert in an slice of size B-A+1.

Solution was benchmarked:

$go test -bench=. -run=^# -benchtime 10s -cpu 1 -benchmem
goos: linux
goarch: amd64
pkg: github.com/looplab/eventhorizon/aggregatestore/events
cpu: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
BenchmarkSort/sortEventsByVersion-1             218145657             55.39 ns/op           16 B/op          1 allocs/op
BenchmarkSort/sortEventsByVersion-10             53875314             216.9 ns/op          160 B/op          1 allocs/op
BenchmarkSort/sortEventsByVersion-100             7211017              1639 ns/op         1792 B/op          1 allocs/op
BenchmarkSort/sortEventsByVersion-1000             627288             18589 ns/op        16384 B/op          1 allocs/op
BenchmarkSortUnsorted
BenchmarkSortUnsorted/sortEventsByVersion-1     220128056             54.52 ns/op           16 B/op          1 allocs/op
BenchmarkSortUnsorted/sortEventsByVersion-10     54352377             219.1 ns/op          160 B/op          1 allocs/op
BenchmarkSortUnsorted/sortEventsByVersion-100     7374812              1629 ns/op         1792 B/op          1 allocs/op
BenchmarkSortUnsorted/sortEventsByVersion-1000     657199             18231 ns/op        16384 B/op          1 allocs/op
PASS
ok      github.com/looplab/eventhorizon/aggregatestore/events   110.407s

Steps to test and verify

aggregatestore_sort_test.go was added.

You can also configure an aggregate with a MongoDB-2 event store.

  1. Create an aggregate
  2. Execute a command in aggregate that generates one or more events
  3. Repeat 2 several times
  4. No errors should be detected
coveralls commented 11 months ago

Coverage Status

coverage: 67.175% (-0.2%) from 67.361% when pulling b92591c29a193821aa7ad157581403a0d1da9b23 on AltScore:fix/409-event-order-application into ac3a97277ea36ba535abd96e0bdad033bd243193 on looplab:main.

MaxBreida commented 11 months ago

Hey, why the decision to do this manual kind of sorting instead of using the sort package?

totemcaf commented 9 months ago

Hey, why the decision to do this manual kind of sorting instead of using the sort package?

The idea is to take advantage of the event structure to improve performance because there was a concern about it.

totemcaf commented 7 months ago

@MaxBreida

Today we suffer in tests from this bug, so I take a new look into it.

I reverted original solution and I provided now a new more modular one.

Basically the mongodb_v2 implementation of the event store will warrant the event order.

For other implementation, a EventSorter wrapper is provided that sort events got by Load and LoadFrom methods.

MaxBreida commented 7 months ago

@MaxBreida

Today we suffer in tests from this bug, so I take a new look into it.

I reverted original solution and I provided now a new more modular one.

Basically the mongodb_v2 implementation of the event store will warrant the event order.

For other implementation, a EventSorter wrapper is provided that sort events got by Load and LoadFrom methods.

I'm unfortunately not a maintainer, was just asking a question while browsing the repo. @maxekman needs to have a look at this.