event sourcing and cqrs from the trenches · from the trenches. universe of users id name username...
TRANSCRIPT
![Page 1: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/1.jpg)
SIDNEY SHEK • ARCHITECT • ATLASSIAN • @SIDNEYSHEK
Event sourcing and CQRSfrom the trenches
![Page 2: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/2.jpg)
![Page 3: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/3.jpg)
Universe of Users
Id Name Username APIKey1 Homer homer d0a2 Bart bart f003 Maggie maggie baa
users
![Page 4: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/4.jpg)
Universe of Users
Id Name Username APIKey1 Homer homer d0a2 Bart bart f003 Lisa Jr maggie baa
users
![Page 5: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/5.jpg)
Universe of Users
Id Name Username APIKey1 Homer homers d0a2 Bart bart f003 Lisa Jr maggie baa
users
![Page 6: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/6.jpg)
Universe of Users
Id Name Username APIKey1 Homer homer d0a2 Bart bart f003 Maggie maggie baa
users
events
Seq Event Time
123 SetUsername(3, Maggie) 0
![Page 7: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/7.jpg)
Universe of Users
Id Name Username APIKey1 Homer homer d0a2 Bart bart f003 Lisa Jr maggie baa
users
events
Seq Event Time
123 SetUsername(3, Maggie) 0
124 SetName(3, Lisa Jr) 10
![Page 8: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/8.jpg)
Universe of Users
Id Name Username APIKey1 Homer homers d0a2 Bart bart f003 Lisa Jr maggie baa
users
events
Seq Event Time
123 SetUsername(3, Maggie) 0
124 SetName(3, Lisa Jr) 10
125 SetUsername(1, homers) 15
![Page 9: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/9.jpg)
Universe of Users
Id Name Username APIKey1 Homer homers d0a2 Bart bart f003 Lisa Jr maggie baa
users
events
Seq Event Time
123 SetUsername(3, Maggie) 0
124 SetName(3, Lisa Jr) 10
125 SetUsername(1, homers) 15
Id Name Derived1 Homer Homer12 Bart Bart23 Lisa Jr Lisa Jr3
users_new
![Page 10: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/10.jpg)
Universe of Users
Id Name Username APIKey1 Homer homers d0a2 Bart bart f003 Lisa Jr maggie baa
users
events
Seq Event Time
123 SetUsername(3, Maggie) 0
124 SetName(3, Lisa Jr) 10
125 SetUsername(1, homers) 15
Id Name Derived1 Homer Homer12 Bart Bart23 Lisa Jr Lisa Jr3
users_new
![Page 11: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/11.jpg)
Our Identity System requirements
![Page 12: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/12.jpg)
Our Identity System requirements
• Users, groups and memberships
![Page 13: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/13.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
![Page 14: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/14.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
• Retrieve by email
![Page 15: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/15.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
• Retrieve by email
• High volume low latency reads
![Page 16: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/16.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
• Retrieve by email
• Incremental synchronisation
• High volume low latency reads
![Page 17: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/17.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
• Retrieve by email
• Incremental synchronisation
• Audit trails for changes
• High volume low latency reads
![Page 18: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/18.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
• Retrieve by email
• Incremental synchronisation
• Audit trails for changes
• High volume low latency reads
• Highly available• Disaster recovery• Zero-downtime upgrades
![Page 19: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/19.jpg)
Our Identity System requirements
• Users, groups and memberships• Searching for users
• Retrieve by email
• Incremental synchronisation
• Audit trails for changes
• High volume low latency reads
• Highly available• Disaster recovery• Zero-downtime upgrades
• Testing with production-like data
![Page 20: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/20.jpg)
Evolving thearchitecture
![Page 21: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/21.jpg)
DynamoDB
SaveAPI
Core app
EventStream
Services
REST callse.g. Add User
Query viewsQuery viewsQuery views
![Page 22: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/22.jpg)
DynamoDB
Commands
Core app
EventStream
Services
REST callse.g. Add User
Query viewsQuery views
Query sync
EventStreamEventStream
Query views
![Page 23: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/23.jpg)
DynamoDB
Commands
Core app
EventStream
Services
REST callse.g. Add User
Query viewsQuery views
Query sync
EventStreamEventStream
Query views
KinesisLambda
ElasticSearch
Events
![Page 24: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/24.jpg)
DynamoDB
Commands
Groups
EventStream
Services
REST callse.g. Add User
Query viewsQuery views
Query sync
EventStreamEventStream
Query views
KinesisLambda
PlatformEvents
Kinesis
ExternalEvents
EventTxf
Users
![Page 25: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/25.jpg)
Delving intocode
![Page 26: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/26.jpg)
Core app stack
Command handlers
Services
Query handlers
Web
post { entity(as[NewUser]) { u => runApi(UserService.addUser(u)) }
command.Op ~> Result
def addUser: AppOp[A]
query.Op ~> Result
type AppOp[A] = Free[App, A] type App[A] = Coproduct[command.Op, query.Op, A]
val runApi: AppOp[A] => Route
case class Save[A](...) extends command.Op[A]case class UserByName[A](...) extends query.Op[A]
![Page 27: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/27.jpg)
Commands save events to streams
object UserCommandHandler { def apply(streams: Streams): command.Op ~> Result = new (command.Op ~> Result) { def apply[X](a: command.Op[X]): Result[X] = a match { case Save(u) =>
case ... } } }
![Page 28: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/28.jpg)
Commands save events to streams
object UserCommandHandler { def apply(streams: Streams): command.Op ~> Result = new (command.Op ~> Result) { def apply[X](a: command.Op[X]): Result[X] = a match { case Save(u) => streams.allUsers.save(SingleStreamId, SetName(u.id, u.name)) .then(streams.userProfile.save(u.id, SetProfile(u)) .thenReturn(u.id) case ... } } }
![Page 29: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/29.jpg)
Query synchroniser is a scalaz-stream Channel…class QuerySynchroniser(db: DB) {
def synchronise(s: Process[Task, StreamEvent]) =
}
![Page 30: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/30.jpg)
Query synchroniser is a scalaz-stream Channel…class QuerySynchroniser(db: DB) {
def synchronise(s: Process[Task, StreamEvent]) = (s through writeEvent).run
private val writeEvent: Channel[Task, StreamEvent, Unit] = Process.constant { e: StreamEvent =>
} }
![Page 31: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/31.jpg)
Query synchroniser is a scalaz-stream Channel…class QuerySynchroniser(db: DB) {
def synchronise(s: Process[Task, StreamEvent]) = (s through writeEvent).run
private val writeEvent: Channel[Task, StreamEvent, Unit] = Process.constant { e: StreamEvent => for { r1 <- StreamState.transitionSeq(db, e.id.key, e.id.seq)
} yield () } }
![Page 32: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/32.jpg)
Query synchroniser is a scalaz-stream Channel…class QuerySynchroniser(db: DB) {
def synchronise(s: Process[Task, StreamEvent]) = (s through writeEvent).run
private val writeEvent: Channel[Task, StreamEvent, Unit] = Process.constant { e: StreamEvent => for { r1 <- StreamState.transitionSeq(db, e.id.key, e.id.seq) _ <- if (r1.success) db.process(e) else db.rollback } yield () } }
![Page 33: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/33.jpg)
…that you pass it an event stream
class KinesisProcessor(qs: QuerySynchroniser) extends IRecordProcessor {
override def processRecords(rs: ProcessRecordInput) = {
}
}
![Page 34: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/34.jpg)
…that you pass it an event stream
class KinesisProcessor(qs: QuerySynchroniser) extends IRecordProcessor {
override def processRecords(rs: ProcessRecordInput) = { // Either emit events from Kinesis, or read events from Dynamo val stream = Process.emitAll { rs.getRecords. ... }
}
}
![Page 35: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/35.jpg)
…that you pass it an event stream
class KinesisProcessor(qs: QuerySynchroniser) extends IRecordProcessor {
override def processRecords(rs: ProcessRecordInput) = { // Either emit events from Kinesis, or read events from Dynamo val stream = Process.emitAll { rs.getRecords. ... }
qs.synchronise(stream).attemptRunFor(...) }
}
![Page 36: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/36.jpg)
Events as an API
![Page 37: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/37.jpg)
AddUser(id, name, email1)
Insert / Update Delta ‘Set’ events
UpdateUser(id, email = Some(email))
SetUserName(id, name)SetUserEmail(id, email1)
SetUserEmail(id, email2)
Fits nicely with CRUD + PATCH
Assume insert before update
Encourages idempotent processing
Minimally sized events to avoid conflict
Single code path for query sync
vs
![Page 38: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/38.jpg)
Sharding forthroughput
Multiple streamsSingle stream
Transactions andconsistent data
resolution
![Page 39: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/39.jpg)
Rules for splitting streams
1. Place independent events on different streams
![Page 40: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/40.jpg)
Rules for splitting streams
1. Place independent events on different streams
2. Split streams by event type and unique Id
![Page 41: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/41.jpg)
Rules for splitting streams
1. Place independent events on different streams
2. Split streams by event type and unique Id
3. Identify the ‘transactions’ you really need
![Page 42: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/42.jpg)
Rules for splitting streams
1. Place independent events on different streams
2. Split streams by event type and unique Id
3. Identify the ‘transactions’ you really need
4. Use hierarchical streams to maximise number of streams
![Page 43: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/43.jpg)
Rules for splitting streams
1. Place independent events on different streams
2. Split streams by event type and unique Id
3. Identify the ‘transactions’ you really need
4. Use hierarchical streams to maximise number of streams
5. Splitting and joining streams later is possible
![Page 44: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/44.jpg)
Let go oftransactions
and consistency
![Page 45: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/45.jpg)
Query views get populated eventually
![Page 46: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/46.jpg)
Query views get populated eventually
• No guaranteed order between events on different streams
![Page 47: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/47.jpg)
Query views get populated eventually
• No guaranteed order between events on different streams
• A field should only be updated by a single event stream
![Page 48: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/48.jpg)
Query views get populated eventually
• No guaranteed order between events on different streams
• A field should only be updated by a single event stream
• No foreign key constraints
![Page 49: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/49.jpg)
Query views get populated eventually
• No guaranteed order between events on different streams
• A field should only be updated by a single event stream
• No foreign key constraints
• Unique or data constraints ‘enforced’ on write
![Page 50: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/50.jpg)
Tokens to emulate transactions and consistency
User: homer (id 4)
All Users: Seq 100
User 4: Seq 23
![Page 51: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/51.jpg)
Tokens to emulate transactions and consistency
• Returned on read and write via ETagUser: homer (id 4)
All Users: Seq 100
User 4: Seq 23
![Page 52: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/52.jpg)
Tokens to emulate transactions and consistency
• Returned on read and write via ETag
• Pass as request header for:
User: homer (id 4)
All Users: Seq 100
User 4: Seq 23
![Page 53: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/53.jpg)
Tokens to emulate transactions and consistency
• Returned on read and write via ETag
• Pass as request header for:• Condition write (‘transaction’)
User: homer (id 4)
All Users: Seq 100
User 4: Seq 23
![Page 54: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/54.jpg)
Tokens to emulate transactions and consistency
• Returned on read and write via ETag
• Pass as request header for:• Condition write (‘transaction’)• Force query view update (‘consistency’)
User: homer (id 4)
All Users: Seq 100
User 4: Seq 23
![Page 55: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/55.jpg)
Tokens to emulate transactions and consistency
• Returned on read and write via ETag
• Pass as request header for:• Condition write (‘transaction’)• Force query view update (‘consistency’)• Caching
User: homer (id 4)
All Users: Seq 100
User 4: Seq 23
![Page 56: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/56.jpg)
Using tokens to enforce state
Client Core App
![Page 57: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/57.jpg)
Using tokens to enforce state
Client Core App
Create User A
![Page 58: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/58.jpg)
Using tokens to enforce state
Client Core App
Create User A
Token TU1
![Page 59: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/59.jpg)
Using tokens to enforce state
Client Core App
Create User A
Create Group B
Token TU1
![Page 60: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/60.jpg)
Using tokens to enforce state
Client Core App
Create User A
Create Group B
Token TU1
Token TG1
![Page 61: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/61.jpg)
Using tokens to enforce state
Client Core App
Create User A
Create Group B
Add User A to Group B (tokens TU1, TG1)
Token TU1
Token TG1
![Page 62: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/62.jpg)
Using tokens to enforce state
Client Core App
Create User A
Create Group B
Add User A to Group B (tokens TU1, TG1)
Force query view to TU1, TG1
Token TU1
Token TG1
![Page 63: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/63.jpg)
Using tokens to enforce state
Client Core App
Create User A
Create Group B
Add User A to Group B (tokens TU1, TG1)
Force query view to TU1, TG1
Token TU1
Token TG1
Token TG2
![Page 64: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/64.jpg)
Key takeaways
![Page 65: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/65.jpg)
Key takeaways
• Start small and challenge everything!
![Page 66: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/66.jpg)
Key takeaways
• Start small and challenge everything!
• Incremental architecture for incremental demos
![Page 67: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/67.jpg)
Key takeaways
• Start small and challenge everything!
• Incremental architecture for incremental demos
• Think “Events as an API”
![Page 68: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/68.jpg)
Key takeaways
• Start small and challenge everything!
• Incremental architecture for incremental demos
• Think “Events as an API”
• Accept weaker transactions and eventual consistency
![Page 69: Event sourcing and CQRS from the trenches · from the trenches. Universe of Users Id Name Username APIKey 1 Homer homer d0a 2 Bart bart f00 3 Maggie maggie baa users. Universe of](https://reader036.vdocuments.us/reader036/viewer/2022070817/5f132a8659939e7c792764a4/html5/thumbnails/69.jpg)
“We should using event sourcing more
than we do”Martin Fowler (very loosely paraphrased)