SlideShare a Scribd company logo
1 of 81
Download to read offline
Event-sourced 
architectures 
with Akka 
@Sander_Mak 
Luminis Technologies
Today's journey 
Event-sourcing 
Actors 
Akka Persistence 
Design for ES
Event-sourcing 
Is all about getting 
the facts straight
Typical 3 layer architecture 
UI/Client 
Service layer 
Database 
fetch ↝ modify ↝ store
Typical 3 layer architecture 
UI/Client 
Service layer 
Database 
fetch ↝ modify ↝ store 
Databases are 
shared mutable state
Typical entity modelling 
Concert 
! 
artist: String 
date: Date 
availableTickets: int 
price: int 
... 
TicketOrder 
! 
noOfTickets: int 
userId: String 
1 *
Typical entity modelling 
Concert 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketOrder 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
noOfTickets = 3 
userId = 1
Typical entity modelling 
Changing the price 
Concert 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketOrder 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
noOfTickets = 3 
userId = 1
Typical entity modelling 
Changing the price 
Concert 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketOrder 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
noOfTickets = 3 
userId = 1 
✘100
Typical entity modelling 
Canceling an order 
Concert 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketOrder 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
noOfTickets = 3 
userId = 1
Typical entity modelling 
Canceling an order 
Concert 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketOrder 
TicketOrder 
! 
noOfTickets = 3 
userId = 1 
! 
noOfTickets = 3 
userId = 1
Update or delete statements in your app? 
Congratulations, you are 
! 
LOSING DATA EVERY DAY
Event-sourced modelling 
ConcertCreated 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketsOrdered 
TicketsOrdered 
! 
noOfTickets = 3 
userId = 1 
TicketsOrdered 
! 
noOfTickets = 3 
! 
userId = 1 
noOfTickets = 3 
userId = 1 
time
Event-sourced modelling 
TicketsOrdered 
TicketsOrdered 
Changing the price 
ConcertCreated 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
TicketsOrdered 
! 
noOfTickets = 3 
userId = 1 
! 
noOfTickets = 3 
! 
userId = 1 
noOfTickets = 3 
userId = 1 
time
Event-sourced modelling 
TicketsOrdered 
TicketsOrdered 
Changing the price 
ConcertCreated 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
PriceChanged 
! 
price = 100 
TicketsOrdered 
! 
noOfTickets = 3 
userId = 1 
! 
noOfTickets = 3 
! 
userId = 1 
noOfTickets = 3 
userId = 1 
time
Event-sourced modelling 
ConcertCreated 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
PriceChanged 
! 
price = 100 
TicketsOrdered 
TicketsOrdered 
! 
noOfTickets = 3 
userId = 1 
TicketsOrdered 
! 
noOfTickets = 3 
! 
userId = 1 
noOfTickets = 3 
userId = 1 
Canceling an order 
time
Event-sourced modelling 
ConcertCreated 
! 
artist = Aerosmith 
availableTickets = 100 
price = 10 
... 
! 
PriceChanged 
! 
price = 100 
OrderCancelled 
! 
userId = 1 
TicketsOrdered 
TicketsOrdered 
! 
noOfTickets = 3 
userId = 1 
TicketsOrdered 
! 
noOfTickets = 3 
! 
userId = 1 
noOfTickets = 3 
userId = 1 
Canceling an order 
time
Event-sourced modelling 
‣ Immutable events 
‣ Append-only storage (scalable) 
‣ Replay events: reconstruct historic state 
‣ Events as audit mechanism 
‣ Events as integration mechanism
Event-sourcing: capture all changes to 
application state as a sequence of events 
Events: where from?
Commands & Events 
Do something (active) 
It happened. 
Deal with it. 
(facts) 
Can be rejected (validation) 
Can be responded to
Querying & event-sourcing 
How do you query a log?
Querying & event-sourcing 
How do you query a log? 
Command 
Query 
Responsibility 
Segregation
CQRS without ES 
Command Query 
UI/Client 
Service layer 
Database
CQRS without ES 
Command Query 
UI/Client 
Service layer 
Database 
Command Query 
UI/Client 
Command 
Model 
Datastore 
Query 
Model(s) 
DaDtaastatosrtoere Datastore 
?
Event-sourced CQRS 
Command Query 
UI/Client 
Command 
Model 
Journal 
Query 
Model(s) 
DaDtaastatosrtoere Datastore 
Events
Actors 
‣ Mature and open source 
‣ Scala & Java API 
‣ Akka Cluster
Actors 
"an island of consistency in a sea of concurrency" 
Actor 
! 
! 
! 
mailbox 
state 
behavior 
async message 
send 
Process message: 
‣ update state 
‣ send messages 
‣ change behavior 
Don't worry about 
concurrency
Actors 
A good fit for event-sourcing? 
Actor 
! 
! 
! 
mailbox 
state 
behavior 
mailbox is non-durable 
(lost messages) 
state is transient
Actors 
Just store all incoming messages? 
Actor 
! 
! 
! 
mailbox 
state 
behavior 
async message 
send 
store in journal 
Problems with 
command-sourcing: 
‣ side-effects 
‣ poisonous 
(failing) messages
Persistence 
‣ Experimental Akka module 
‣ Scala & Java API 
‣ Actor state persistence based 
on event-sourcing
Persistent Actor 
PersistentActor 
actor-id 
! 
! 
state 
! 
event 
async message 
send (command) 
‣ Derive events from 
commands 
‣ Store events 
‣ Update state 
‣ Perform side-effects 
event 
journal (actor-id)
Persistent Actor 
PersistentActor 
actor-id 
! 
! 
state 
! 
event 
! 
Recover by replaying 
events, that update the 
state (no side-effects) 
! 
event 
journal (actor-id)
Persistent Actor 
! 
case object Increment // command 
case object Incremented // event 
! 
class CounterActor extends PersistentActor { 
def persistenceId = "counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
} 
}
Persistent Actor 
! 
case object Increment // command 
case object Incremented // event 
! 
class CounterActor extends PersistentActor { 
def persistenceId = "counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
} 
}
Persistent Actor 
! 
case object Increment // command 
case object Incremented // event 
! 
class CounterActor extends PersistentActor { 
def persistenceId = "counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
} 
} 
async callback 
(but safe to close 
over state)
Persistent Actor 
! 
case object Increment // command 
case object Incremented // event 
! 
class CounterActor extends PersistentActor { 
def persistenceId = "counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
} 
}
Persistent Actor 
! 
case object Increment // command 
case object Incremented // event 
! 
class CounterActor extends PersistentActor { 
def persistenceId = "counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
} 
} 
Isn't recovery 
with lots of events 
slow?
Snapshots 
class SnapshottingCounterActor extends PersistentActor { 
def persistenceId = "snapshotting-counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
case "takesnapshot" => saveSnapshot(state) 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
case SnapshotOffer(_, snapshotState: Int) => state = snapshotState 
} 
}
Snapshots 
class SnapshottingCounterActor extends PersistentActor { 
def persistenceId = "snapshotting-counter" 
! 
var state = 0 
! 
val receiveCommand: Receive = { 
case Increment => persist(Incremented) { evt => 
state += 1 
println("incremented") 
} 
case "takesnapshot" => saveSnapshot(state) 
} 
! 
val receiveRecover: Receive = { 
case Incremented => state += 1 
case SnapshotOffer(_, snapshotState: Int) => state = snapshotState 
} 
}
Journal & Snapshot 
Cassandra 
Cassandra 
Kafka Kafka 
MongoDB 
HBase 
DynamoDB 
MongoDB 
HBase 
MapDB 
JDBC JDBC 
Plugins:
Plugins: 
Serialization 
Default: Java serialization 
Pluggable through Akka: 
‣ Protobuf 
‣ Kryo 
‣ Avro 
‣ Your own
Persistent View 
Persistent 
Actor 
journal 
Persistent 
View 
Persistent 
View 
Views poll the journal 
‣ Eventually consistent 
‣ Polling configurable 
‣ Actor may be inactive 
‣ Views track single 
persistence-id 
‣ Views can have own 
snapshots 
snapshot store 
other 
datastore
Persistent View 
! 
"The Database is a cache 
of a subset of the log" 
- Pat Helland 
Persistent 
Actor 
journal 
Persistent 
View 
Persistent 
View 
snapshot store 
other 
datastore
Persistent View 
! 
case object ComplexQuery 
class CounterView extends PersistentView { 
override def persistenceId: String = "counter" 
override def viewId: String = "counter-view" 
var queryState = 0 
def receive: Receive = { 
case Incremented if isPersistent => { 
queryState = someVeryComplicatedCalculation(queryState) 
// Or update a document/graph/relational database 
} 
case ComplexQuery => { 
sender() ! queryState; 
// Or perform specialized query on datastore 
} 
} 
}
Persistent View 
! 
case object ComplexQuery 
class CounterView extends PersistentView { 
override def persistenceId: String = "counter" 
override def viewId: String = "counter-view" 
var queryState = 0 
def receive: Receive = { 
case Incremented if isPersistent => { 
queryState = someVeryComplicatedCalculation(queryState) 
// Or update a document/graph/relational database 
} 
case ComplexQuery => { 
sender() ! queryState; 
// Or perform specialized query on datastore 
} 
} 
}
Persistent View 
! 
case object ComplexQuery 
class CounterView extends PersistentView { 
override def persistenceId: String = "counter" 
override def viewId: String = "counter-view" 
var queryState = 0 
def receive: Receive = { 
case Incremented if isPersistent => { 
queryState = someVeryComplicatedCalculation(queryState) 
// Or update a document/graph/relational database 
} 
case ComplexQuery => { 
sender() ! queryState; 
// Or perform specialized query on datastore 
} 
} 
}
Sell concert tickets 
ConcertActor 
! 
! 
price 
availableTickets 
startTime 
salesRecords 
! 
Commands: 
CreateConcert 
BuyTickets 
ChangePrice 
AddCapacity 
journal 
ConcertHistoryView 
! 
! 
! 
! 
60 
45 
30 
15 
0 
100 
50 
0 
$50 $75 $100 
code @ bit.ly/akka-es
Scaling out: Akka Cluster 
Single writer: persistent actor must be singleton, views may be anywhere 
Cluster node Cluster node Cluster node 
Persistent 
Persistent 
Actor 
id = "1" 
Actor 
id = "1" 
Persistent 
Actor 
id = "1" 
Persistent 
Actor 
id = "2" 
Persistent 
Actor 
id = "1" 
Persistent 
Actor 
id = "3" 
distributed journal
Scaling out: Akka Cluster 
Single writer: persistent actor must be singleton, views may be anywhere 
How are persistent actors distributed over cluster? 
Cluster node Cluster node Cluster node 
Persistent 
Persistent 
Actor 
id = "1" 
Actor 
id = "1" 
Persistent 
Actor 
id = "1" 
Persistent 
Actor 
id = "2" 
Persistent 
Actor 
id = "1" 
Persistent 
Actor 
id = "3" 
distributed journal
Scaling out: Akka Cluster 
Sharding: Coordinator assigns ShardRegions to nodes (consistent hashing) 
Actors in shard can be activated/passivated, rebalanced 
Cluster node Cluster node Cluster node 
Persistent 
Persistent 
Actor 
id = "1" 
Actor 
id = "1" 
Persistent 
Actor 
id = "1" 
Persistent 
Actor 
id = "2" 
Persistent 
Actor 
id = "1" 
Persistent 
Actor 
id = "3" 
Shard 
Region 
Shard 
Region 
Shard 
Region 
Coordinator 
distributed journal
Scaling out: Sharding 
val idExtractor: ShardRegion.IdExtractor = { 
case cmd: Command => (cmd.concertId, cmd) 
} 
IdExtractor allows ShardRegion 
to route commands to actors
Scaling out: Sharding 
val idExtractor: ShardRegion.IdExtractor = { 
case cmd: Command => (cmd.concertId, cmd) 
} 
IdExtractor allows ShardRegion 
to route commands to actors 
val shardResolver: ShardRegion.ShardResolver = 
msg => msg match { 
case cmd: Command => hash(cmd.concertId) 
} 
ShardResolver assigns new 
actors to shards
Scaling out: Sharding 
val idExtractor: ShardRegion.IdExtractor = { 
case cmd: Command => (cmd.concertId, cmd) 
} 
IdExtractor allows ShardRegion 
to route commands to actors 
val shardResolver: ShardRegion.ShardResolver = 
msg => msg match { 
case cmd: Command => hash(cmd.concertId) 
} 
ShardResolver assigns new 
actors to shards 
ClusterSharding(system).start( 
typeName = "Concert", 
entryProps = Some(ConcertActor.props()), 
idExtractor = ConcertActor.idExtractor, 
shardResolver = ConcertActor.shardResolver) 
Initialize ClusterSharding 
extension
Scaling out: Sharding 
val idExtractor: ShardRegion.IdExtractor = { 
case cmd: Command => (cmd.concertId, cmd) 
} 
IdExtractor allows ShardRegion 
to route commands to actors 
val shardResolver: ShardRegion.ShardResolver = 
msg => msg match { 
case cmd: Command => hash(cmd.concertId) 
} 
ShardResolver assigns new 
actors to shards 
ClusterSharding(system).start( 
typeName = "Concert", 
entryProps = Some(ConcertActor.props()), 
idExtractor = ConcertActor.idExtractor, 
shardResolver = ConcertActor.shardResolver) 
Initialize ClusterSharding 
extension 
val concertRegion: ActorRef = ClusterSharding(system).shardRegion("Concert") 
concertRegion ! BuyTickets(concertId = 123, user = "Sander", quantity = 1)
Design for event-sourcing
DDD+CQRS+ES 
DDD: Domain Driven Design 
Fully consistent Fully consistent 
Aggregate 
! 
Aggregate 
! 
Eventual 
Consistency 
Root entity 
enteitnytity entity 
Root entity 
entity entity
DDD+CQRS+ES 
DDD: Domain Driven Design 
Fully consistent Fully consistent 
Aggregate 
! 
Aggregate 
! 
Eventual 
Consistency 
Root entity 
enteitnytity entity 
Root entity 
entity entity 
Persistent 
Actor 
Persistent 
Actor 
Message 
passing
DDD+CQRS+ES 
DDD: Domain Driven Design 
Fully consistent Fully consistent 
Aggregate 
! 
Aggregate 
! 
Eventual 
Consistency 
Akka Persistence is not a DDD/CQRS framework 
But it comes awfully close 
Root entity 
enteitnytity entity 
Root entity 
entity entity 
Persistent 
Actor 
Persistent 
Actor 
Message 
passing
Designing aggregates 
Focus on events 
Structural representation(s) follow ERD
Designing aggregates 
Focus on events 
Structural representation(s) follow ERD 
Size matters. Faster replay, less write contention 
Don't store derived info (use views)
Designing aggregates 
Focus on events 
Structural representation(s) follow ERD 
Size matters. Faster replay, less write contention 
Don't store derived info (use views) 
With CQRS read-your-writes is not the default 
When you need this, model it in a single Aggregate
Between aggregates 
‣ Send commands to other aggregates by id 
! 
‣ No distributed transactions 
‣ Use business level ack/nacks 
‣ SendInvoice -> InvoiceSent/InvoiceCouldNotBeSent 
‣ Compensating actions for failure 
‣ No guaranteed delivery 
‣ Alternative: AtLeastOnceDelivery
Between systems 
System integration through event-sourcing 
topic 1 topic 2 derived 
Kafka 
Application 
Akka 
Persistence 
Spark 
Streaming 
External 
Application
Designing commands 
‣ Self-contained 
‣ Unit of atomic change 
‣ Granularity and intent
Designing commands 
‣ Self-contained 
‣ Unit of atomic change 
‣ Granularity and intent 
UpdateAddress 
street = ... 
city = ... vs 
ChangeStreet 
street = ... 
ChangeCity 
street = ...
Designing commands 
‣ Self-contained 
‣ Unit of atomic change 
‣ Granularity and intent 
UpdateAddress 
street = ... 
city = ... vs 
ChangeStreet 
street = ... 
ChangeCity 
street = ... 
Move 
street = ... 
city = ... vs
Designing events 
CreateConcert
Designing events 
CreateConcert ConcertCreated 
Past tense 
Irrefutable
Designing events 
CreateConcert ConcertCreated 
Past tense 
Irrefutable 
TicketsBought 
newCapacity = 99
Designing events 
CreateConcert ConcertCreated 
Past tense 
Irrefutable 
TicketsBought 
newCapacity = 99 
TicketsBought 
quantity = 1 
Delta-based 
No derived info
Designing events 
CreateConcert 
ConcertCreated 
ConcertCreated 
Past tense 
Irrefutable 
TicketsBought 
newCapacity = 99 
TicketsBought 
quantity = 1 
Delta-based 
No derived info
Designing events 
CreateConcert 
ConcertCreated ConcertCreated 
who/when/.. 
Add metadata 
to all events 
ConcertCreated 
Past tense 
Irrefutable 
TicketsBought 
newCapacity = 99 
TicketsBought 
quantity = 1 
Delta-based 
No derived info
Versioning 
Actor logic: 
v1 and v2 
event v2 
event v2 
event v1 
event v1
Versioning 
Actor logic: 
v1 and v2 
event v2 
event v2 
event v1 
event v1 
Actor logic: 
v2 
event v2 
event v2 
event v2 
event v1 
event v2 
event v1
Versioning 
Actor logic: 
v1 and v2 
event v2 
event v2 
event v1 
event v1 
Actor logic: 
v2 
event v2 
event v2 
event v2 
event v1 
event v2 
event v1 
Actor logic: 
v2 
event v2 
event v2 
snapshot 
event v1 
event v1
Versioning 
Actor logic: 
v1 and v2 
event v2 
event v2 
event v1 
event v1 
Actor logic: 
v2 
event v2 
event v2 
event v2 
event v1 
event v2 
event v1 
Actor logic: 
v2 
event v2 
event v2 
snapshot 
event v1 
event v1 
‣ Be backwards 
compatible 
‣ Avro/Protobuf 
‣ Serializer can do 
translation 
! 
‣ Snapshot 
versioning: 
harder
In conclusion 
Event-sourcing is... 
Powerful 
but unfamiliar
In conclusion 
Event-sourcing is... 
Powerful 
but unfamiliar 
Combines well with 
UI/Client 
Command 
Model 
Journal 
Query 
Model 
DaDtaastatosrtoere Datastore 
Events 
DDD/CQRS
In conclusion 
Event-sourcing is... 
Powerful 
but unfamiliar 
Combines well with 
UI/Client 
Command 
Model 
Journal 
Query 
Model 
DaDtaastatosrtoere Datastore 
Events 
DDD/CQRS 
Not a
In conclusion 
Akka Actors & Akka Persistence 
A good fit for 
event-sourcing 
PersistentActor 
actor-id 
! 
! 
state 
! 
async message 
send 
(command) 
event 
event 
journal (actor-id) 
Experimental, view 
improvements needed
Thank you. 
! 
code @ bit.ly/akka-es 
@Sander_Mak 
Luminis Technologies

More Related Content

What's hot

CLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsCLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsForrest Norvell
 
Deep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceAmazon Web Services
 
Masterclass Advanced Usage of the AWS CLI
Masterclass Advanced Usage of the AWS CLIMasterclass Advanced Usage of the AWS CLI
Masterclass Advanced Usage of the AWS CLIDanilo Poccia
 
A Crash Course on Serverless Applications in Python
A Crash Course on Serverless Applications in PythonA Crash Course on Serverless Applications in Python
A Crash Course on Serverless Applications in PythonJames Saryerwinnie
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with JasmineTim Tyrrell
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Ben Lesh
 
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014Amazon Web Services
 
Akka Futures and Akka Remoting
Akka Futures  and Akka RemotingAkka Futures  and Akka Remoting
Akka Futures and Akka RemotingKnoldus Inc.
 
(DEV301) Automating AWS with the AWS CLI
(DEV301) Automating AWS with the AWS CLI(DEV301) Automating AWS with the AWS CLI
(DEV301) Automating AWS with the AWS CLIAmazon Web Services
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...it-people
 
CPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolsCPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolscharsbar
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the mastersAra Pehlivanian
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerIslam Sharabash
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projectsIgnacio Martín
 
Actor Clustering with Docker Containers and Akka.Net in F#
Actor Clustering with Docker Containers and Akka.Net in F#Actor Clustering with Docker Containers and Akka.Net in F#
Actor Clustering with Docker Containers and Akka.Net in F#Riccardo Terrell
 
Writing Go(od) Tests (FOSDEM 2020)
Writing Go(od) Tests (FOSDEM 2020)Writing Go(od) Tests (FOSDEM 2020)
Writing Go(od) Tests (FOSDEM 2020)Nikki Attea
 

What's hot (20)

CLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.jsCLS & asyncListener: asynchronous observability for Node.js
CLS & asyncListener: asynchronous observability for Node.js
 
Deep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line InterfaceDeep Dive: AWS Command Line Interface
Deep Dive: AWS Command Line Interface
 
Masterclass Advanced Usage of the AWS CLI
Masterclass Advanced Usage of the AWS CLIMasterclass Advanced Usage of the AWS CLI
Masterclass Advanced Usage of the AWS CLI
 
A Crash Course on Serverless Applications in Python
A Crash Course on Serverless Applications in PythonA Crash Course on Serverless Applications in Python
A Crash Course on Serverless Applications in Python
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with Jasmine
 
Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016Async Redux Actions With RxJS - React Rally 2016
Async Redux Actions With RxJS - React Rally 2016
 
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
 
Akka Futures and Akka Remoting
Akka Futures  and Akka RemotingAkka Futures  and Akka Remoting
Akka Futures and Akka Remoting
 
(DEV301) Automating AWS with the AWS CLI
(DEV301) Automating AWS with the AWS CLI(DEV301) Automating AWS with the AWS CLI
(DEV301) Automating AWS with the AWS CLI
 
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
«Как сделать так, чтобы тесты на Swift не причиняли боль» Сычев Александр, Ra...
 
CPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolsCPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its tools
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
Concurrecny inf sharp
Concurrecny inf sharpConcurrecny inf sharp
Concurrecny inf sharp
 
Expert JavaScript tricks of the masters
Expert JavaScript  tricks of the mastersExpert JavaScript  tricks of the masters
Expert JavaScript tricks of the masters
 
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListenerNode.js: Continuation-Local-Storage and the Magic of AsyncListener
Node.js: Continuation-Local-Storage and the Magic of AsyncListener
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Internal Hive
Internal HiveInternal Hive
Internal Hive
 
Akka patterns
Akka patternsAkka patterns
Akka patterns
 
Actor Clustering with Docker Containers and Akka.Net in F#
Actor Clustering with Docker Containers and Akka.Net in F#Actor Clustering with Docker Containers and Akka.Net in F#
Actor Clustering with Docker Containers and Akka.Net in F#
 
Writing Go(od) Tests (FOSDEM 2020)
Writing Go(od) Tests (FOSDEM 2020)Writing Go(od) Tests (FOSDEM 2020)
Writing Go(od) Tests (FOSDEM 2020)
 

Viewers also liked

Dependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake PatternDependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake PatternDebasish Ghosh
 
The Good, The Bad and The Ugly of Event Sourcing
The Good, The Bad and The Ugly of Event SourcingThe Good, The Bad and The Ugly of Event Sourcing
The Good, The Bad and The Ugly of Event SourcingDennis Doomen
 
The Why and How of Scala at Twitter
The Why and How of Scala at TwitterThe Why and How of Scala at Twitter
The Why and How of Scala at TwitterAlex Payne
 
Microservice Architecuture with Event Sourcing @ Sydney JVM Meetup
Microservice Architecuture with Event Sourcing @ Sydney JVM MeetupMicroservice Architecuture with Event Sourcing @ Sydney JVM Meetup
Microservice Architecuture with Event Sourcing @ Sydney JVM MeetupBoris Kravtsov
 
Event Sourcing using Akka on AWS
Event Sourcing using Akka on AWSEvent Sourcing using Akka on AWS
Event Sourcing using Akka on AWSDaniel Pfeiffer
 
Java and the blockchain - introducing web3j
Java and the blockchain - introducing web3jJava and the blockchain - introducing web3j
Java and the blockchain - introducing web3jConor Svensson
 

Viewers also liked (6)

Dependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake PatternDependency Injection in Scala - Beyond the Cake Pattern
Dependency Injection in Scala - Beyond the Cake Pattern
 
The Good, The Bad and The Ugly of Event Sourcing
The Good, The Bad and The Ugly of Event SourcingThe Good, The Bad and The Ugly of Event Sourcing
The Good, The Bad and The Ugly of Event Sourcing
 
The Why and How of Scala at Twitter
The Why and How of Scala at TwitterThe Why and How of Scala at Twitter
The Why and How of Scala at Twitter
 
Microservice Architecuture with Event Sourcing @ Sydney JVM Meetup
Microservice Architecuture with Event Sourcing @ Sydney JVM MeetupMicroservice Architecuture with Event Sourcing @ Sydney JVM Meetup
Microservice Architecuture with Event Sourcing @ Sydney JVM Meetup
 
Event Sourcing using Akka on AWS
Event Sourcing using Akka on AWSEvent Sourcing using Akka on AWS
Event Sourcing using Akka on AWS
 
Java and the blockchain - introducing web3j
Java and the blockchain - introducing web3jJava and the blockchain - introducing web3j
Java and the blockchain - introducing web3j
 

Similar to Event-sourced architectures with Akka - Sander Mak

Resilient Applications with Akka Persistence - Scaladays 2014
Resilient Applications with Akka Persistence - Scaladays 2014Resilient Applications with Akka Persistence - Scaladays 2014
Resilient Applications with Akka Persistence - Scaladays 2014Björn Antonsson
 
HBase RowKey design for Akka Persistence
HBase RowKey design for Akka PersistenceHBase RowKey design for Akka Persistence
HBase RowKey design for Akka PersistenceKonrad Malawski
 
Using Akka Persistence to build a configuration datastore
Using Akka Persistence to build a configuration datastoreUsing Akka Persistence to build a configuration datastore
Using Akka Persistence to build a configuration datastoreAnargyros Kiourkos
 
Data in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyData in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyMartin Zapletal
 
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術名辰 洪
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSAdam L Barrett
 
Reactive Summit 2017
Reactive Summit 2017Reactive Summit 2017
Reactive Summit 2017janm399
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simplerAlexander Mostovenko
 
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...GeeksLab Odessa
 
Server Side Events
Server Side EventsServer Side Events
Server Side Eventsthepilif
 
Implementing Server Side Data Synchronization for Mobile Apps
Implementing Server Side Data Synchronization for Mobile AppsImplementing Server Side Data Synchronization for Mobile Apps
Implementing Server Side Data Synchronization for Mobile AppsMichele Orselli
 
Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2Martin Zapletal
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptViliam Elischer
 
Event-sourced systems with Kafka, Clojure, and Jackdaw
Event-sourced systems with Kafka, Clojure, and JackdawEvent-sourced systems with Kafka, Clojure, and Jackdaw
Event-sourced systems with Kafka, Clojure, and JackdawBryce Covert
 
React.js: Beyond the Browser
React.js: Beyond the BrowserReact.js: Beyond the Browser
React.js: Beyond the Browsergarbles
 
Casting for not so strange actors
Casting for not so strange actorsCasting for not so strange actors
Casting for not so strange actorszucaritask
 

Similar to Event-sourced architectures with Akka - Sander Mak (20)

Resilient Applications with Akka Persistence - Scaladays 2014
Resilient Applications with Akka Persistence - Scaladays 2014Resilient Applications with Akka Persistence - Scaladays 2014
Resilient Applications with Akka Persistence - Scaladays 2014
 
HBase RowKey design for Akka Persistence
HBase RowKey design for Akka PersistenceHBase RowKey design for Akka Persistence
HBase RowKey design for Akka Persistence
 
Using Akka Persistence to build a configuration datastore
Using Akka Persistence to build a configuration datastoreUsing Akka Persistence to build a configuration datastore
Using Akka Persistence to build a configuration datastore
 
Kotlin Redux
Kotlin ReduxKotlin Redux
Kotlin Redux
 
Data in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data EfficientlyData in Motion: Streaming Static Data Efficiently
Data in Motion: Streaming Static Data Efficiently
 
RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術RxJS - 封裝程式的藝術
RxJS - 封裝程式的藝術
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Advanced redux
Advanced reduxAdvanced redux
Advanced redux
 
Reactive Summit 2017
Reactive Summit 2017Reactive Summit 2017
Reactive Summit 2017
 
rx.js make async programming simpler
rx.js make async programming simplerrx.js make async programming simpler
rx.js make async programming simpler
 
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
WebCamp:Front-end Developers Day. Александр Мостовенко "Rx.js - делаем асинхр...
 
Rxjs kyivjs 2015
Rxjs kyivjs 2015Rxjs kyivjs 2015
Rxjs kyivjs 2015
 
Server Side Events
Server Side EventsServer Side Events
Server Side Events
 
ReactJS
ReactJSReactJS
ReactJS
 
Implementing Server Side Data Synchronization for Mobile Apps
Implementing Server Side Data Synchronization for Mobile AppsImplementing Server Side Data Synchronization for Mobile Apps
Implementing Server Side Data Synchronization for Mobile Apps
 
Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2Data in Motion: Streaming Static Data Efficiently 2
Data in Motion: Streaming Static Data Efficiently 2
 
RxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScriptRxJS - The Reactive extensions for JavaScript
RxJS - The Reactive extensions for JavaScript
 
Event-sourced systems with Kafka, Clojure, and Jackdaw
Event-sourced systems with Kafka, Clojure, and JackdawEvent-sourced systems with Kafka, Clojure, and Jackdaw
Event-sourced systems with Kafka, Clojure, and Jackdaw
 
React.js: Beyond the Browser
React.js: Beyond the BrowserReact.js: Beyond the Browser
React.js: Beyond the Browser
 
Casting for not so strange actors
Casting for not so strange actorsCasting for not so strange actors
Casting for not so strange actors
 

More from NLJUG

The future of Web-Scale - Johan Tillema, Rene Boere & Chris Quach
The future of Web-Scale - Johan Tillema, Rene Boere & Chris QuachThe future of Web-Scale - Johan Tillema, Rene Boere & Chris Quach
The future of Web-Scale - Johan Tillema, Rene Boere & Chris QuachNLJUG
 
Speedy perception trumps speedy reception–smart asynchronous interactions - L...
Speedy perception trumps speedy reception–smart asynchronous interactions - L...Speedy perception trumps speedy reception–smart asynchronous interactions - L...
Speedy perception trumps speedy reception–smart asynchronous interactions - L...NLJUG
 
Decoding the airspace above you with Java and $7 hardware - Bert Jan Schrijver
Decoding the airspace above you with Java and $7 hardware - Bert Jan SchrijverDecoding the airspace above you with Java and $7 hardware - Bert Jan Schrijver
Decoding the airspace above you with Java and $7 hardware - Bert Jan SchrijverNLJUG
 
Using Docker to Develop, Test and Run Maven Projects - Wouter Danes
Using Docker to Develop, Test and Run Maven Projects - Wouter DanesUsing Docker to Develop, Test and Run Maven Projects - Wouter Danes
Using Docker to Develop, Test and Run Maven Projects - Wouter DanesNLJUG
 
Kill the mutants and test your tests - Roy van Rijn
Kill the mutants and test your tests - Roy van RijnKill the mutants and test your tests - Roy van Rijn
Kill the mutants and test your tests - Roy van RijnNLJUG
 
Real-time user interfaces - sosm gewoon makkelijker - Allard Buijze
Real-time user interfaces - sosm gewoon makkelijker - Allard BuijzeReal-time user interfaces - sosm gewoon makkelijker - Allard Buijze
Real-time user interfaces - sosm gewoon makkelijker - Allard BuijzeNLJUG
 
The end of traditional enterprise IT - ING's journey to the next generation I...
The end of traditional enterprise IT - ING's journey to the next generation I...The end of traditional enterprise IT - ING's journey to the next generation I...
The end of traditional enterprise IT - ING's journey to the next generation I...NLJUG
 
Performance van Java 8 en verder - Jeroen Borgers
Performance van Java 8 en verder - Jeroen BorgersPerformance van Java 8 en verder - Jeroen Borgers
Performance van Java 8 en verder - Jeroen BorgersNLJUG
 
Introduction to Reactive with Play and Akka - Markus Jura
Introduction to Reactive with Play and Akka - Markus JuraIntroduction to Reactive with Play and Akka - Markus Jura
Introduction to Reactive with Play and Akka - Markus JuraNLJUG
 
Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...
Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...
Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...NLJUG
 
Workshop angular dart presentatie - Atos
Workshop angular dart presentatie - AtosWorkshop angular dart presentatie - Atos
Workshop angular dart presentatie - AtosNLJUG
 
Workshop spring boot presentatie - Atos
Workshop spring boot presentatie - AtosWorkshop spring boot presentatie - Atos
Workshop spring boot presentatie - AtosNLJUG
 
Cultivating the jenkins job jungle with groovy - Patrick van Dissel
Cultivating the jenkins job jungle with groovy - Patrick van DisselCultivating the jenkins job jungle with groovy - Patrick van Dissel
Cultivating the jenkins job jungle with groovy - Patrick van DisselNLJUG
 
Rethink your architecture - Marten Deinum
Rethink your architecture - Marten DeinumRethink your architecture - Marten Deinum
Rethink your architecture - Marten DeinumNLJUG
 
Evolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopper
Evolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopperEvolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopper
Evolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopperNLJUG
 
Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...
Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...
Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...NLJUG
 
Apache Wicket: 10 jaar en verder - Martijn Dashorst
Apache Wicket: 10 jaar en verder - Martijn DashorstApache Wicket: 10 jaar en verder - Martijn Dashorst
Apache Wicket: 10 jaar en verder - Martijn DashorstNLJUG
 
Opening - Bert Ertman
Opening - Bert ErtmanOpening - Bert Ertman
Opening - Bert ErtmanNLJUG
 
Returning the right results - Jettro Coenradie
Returning the right results - Jettro CoenradieReturning the right results - Jettro Coenradie
Returning the right results - Jettro CoenradieNLJUG
 
Reactive programming met Java 8 en Java EE 7 - Martijn Blankestijn
Reactive programming met Java 8 en Java EE 7 - Martijn BlankestijnReactive programming met Java 8 en Java EE 7 - Martijn Blankestijn
Reactive programming met Java 8 en Java EE 7 - Martijn BlankestijnNLJUG
 

More from NLJUG (20)

The future of Web-Scale - Johan Tillema, Rene Boere & Chris Quach
The future of Web-Scale - Johan Tillema, Rene Boere & Chris QuachThe future of Web-Scale - Johan Tillema, Rene Boere & Chris Quach
The future of Web-Scale - Johan Tillema, Rene Boere & Chris Quach
 
Speedy perception trumps speedy reception–smart asynchronous interactions - L...
Speedy perception trumps speedy reception–smart asynchronous interactions - L...Speedy perception trumps speedy reception–smart asynchronous interactions - L...
Speedy perception trumps speedy reception–smart asynchronous interactions - L...
 
Decoding the airspace above you with Java and $7 hardware - Bert Jan Schrijver
Decoding the airspace above you with Java and $7 hardware - Bert Jan SchrijverDecoding the airspace above you with Java and $7 hardware - Bert Jan Schrijver
Decoding the airspace above you with Java and $7 hardware - Bert Jan Schrijver
 
Using Docker to Develop, Test and Run Maven Projects - Wouter Danes
Using Docker to Develop, Test and Run Maven Projects - Wouter DanesUsing Docker to Develop, Test and Run Maven Projects - Wouter Danes
Using Docker to Develop, Test and Run Maven Projects - Wouter Danes
 
Kill the mutants and test your tests - Roy van Rijn
Kill the mutants and test your tests - Roy van RijnKill the mutants and test your tests - Roy van Rijn
Kill the mutants and test your tests - Roy van Rijn
 
Real-time user interfaces - sosm gewoon makkelijker - Allard Buijze
Real-time user interfaces - sosm gewoon makkelijker - Allard BuijzeReal-time user interfaces - sosm gewoon makkelijker - Allard Buijze
Real-time user interfaces - sosm gewoon makkelijker - Allard Buijze
 
The end of traditional enterprise IT - ING's journey to the next generation I...
The end of traditional enterprise IT - ING's journey to the next generation I...The end of traditional enterprise IT - ING's journey to the next generation I...
The end of traditional enterprise IT - ING's journey to the next generation I...
 
Performance van Java 8 en verder - Jeroen Borgers
Performance van Java 8 en verder - Jeroen BorgersPerformance van Java 8 en verder - Jeroen Borgers
Performance van Java 8 en verder - Jeroen Borgers
 
Introduction to Reactive with Play and Akka - Markus Jura
Introduction to Reactive with Play and Akka - Markus JuraIntroduction to Reactive with Play and Akka - Markus Jura
Introduction to Reactive with Play and Akka - Markus Jura
 
Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...
Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...
Web-scale op basis van Hadoop en Akka Reactive Streams - Johan Tillema, Rene ...
 
Workshop angular dart presentatie - Atos
Workshop angular dart presentatie - AtosWorkshop angular dart presentatie - Atos
Workshop angular dart presentatie - Atos
 
Workshop spring boot presentatie - Atos
Workshop spring boot presentatie - AtosWorkshop spring boot presentatie - Atos
Workshop spring boot presentatie - Atos
 
Cultivating the jenkins job jungle with groovy - Patrick van Dissel
Cultivating the jenkins job jungle with groovy - Patrick van DisselCultivating the jenkins job jungle with groovy - Patrick van Dissel
Cultivating the jenkins job jungle with groovy - Patrick van Dissel
 
Rethink your architecture - Marten Deinum
Rethink your architecture - Marten DeinumRethink your architecture - Marten Deinum
Rethink your architecture - Marten Deinum
 
Evolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopper
Evolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopperEvolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopper
Evolutionary Algorithms: the key to solving complex Java puzzles! - Bas knopper
 
Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...
Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...
Modularity and Domain Driven Design; a killer Combination? - Tom de Wolf & St...
 
Apache Wicket: 10 jaar en verder - Martijn Dashorst
Apache Wicket: 10 jaar en verder - Martijn DashorstApache Wicket: 10 jaar en verder - Martijn Dashorst
Apache Wicket: 10 jaar en verder - Martijn Dashorst
 
Opening - Bert Ertman
Opening - Bert ErtmanOpening - Bert Ertman
Opening - Bert Ertman
 
Returning the right results - Jettro Coenradie
Returning the right results - Jettro CoenradieReturning the right results - Jettro Coenradie
Returning the right results - Jettro Coenradie
 
Reactive programming met Java 8 en Java EE 7 - Martijn Blankestijn
Reactive programming met Java 8 en Java EE 7 - Martijn BlankestijnReactive programming met Java 8 en Java EE 7 - Martijn Blankestijn
Reactive programming met Java 8 en Java EE 7 - Martijn Blankestijn
 

Recently uploaded

Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????blackmambaettijean
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embeddingZilliz
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 

Recently uploaded (20)

Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
What is Artificial Intelligence?????????
What is Artificial Intelligence?????????What is Artificial Intelligence?????????
What is Artificial Intelligence?????????
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Training state-of-the-art general text embedding
Training state-of-the-art general text embeddingTraining state-of-the-art general text embedding
Training state-of-the-art general text embedding
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 

Event-sourced architectures with Akka - Sander Mak

  • 1. Event-sourced architectures with Akka @Sander_Mak Luminis Technologies
  • 2. Today's journey Event-sourcing Actors Akka Persistence Design for ES
  • 3. Event-sourcing Is all about getting the facts straight
  • 4. Typical 3 layer architecture UI/Client Service layer Database fetch ↝ modify ↝ store
  • 5. Typical 3 layer architecture UI/Client Service layer Database fetch ↝ modify ↝ store Databases are shared mutable state
  • 6. Typical entity modelling Concert ! artist: String date: Date availableTickets: int price: int ... TicketOrder ! noOfTickets: int userId: String 1 *
  • 7. Typical entity modelling Concert ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketOrder TicketOrder ! noOfTickets = 3 userId = 1 TicketOrder ! noOfTickets = 3 userId = 1 noOfTickets = 3 userId = 1
  • 8. Typical entity modelling Changing the price Concert ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketOrder TicketOrder ! noOfTickets = 3 userId = 1 TicketOrder ! noOfTickets = 3 userId = 1 noOfTickets = 3 userId = 1
  • 9. Typical entity modelling Changing the price Concert ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketOrder TicketOrder ! noOfTickets = 3 userId = 1 TicketOrder ! noOfTickets = 3 userId = 1 noOfTickets = 3 userId = 1 ✘100
  • 10. Typical entity modelling Canceling an order Concert ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketOrder TicketOrder ! noOfTickets = 3 userId = 1 TicketOrder ! noOfTickets = 3 userId = 1 noOfTickets = 3 userId = 1
  • 11. Typical entity modelling Canceling an order Concert ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketOrder TicketOrder ! noOfTickets = 3 userId = 1 ! noOfTickets = 3 userId = 1
  • 12. Update or delete statements in your app? Congratulations, you are ! LOSING DATA EVERY DAY
  • 13. Event-sourced modelling ConcertCreated ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketsOrdered TicketsOrdered ! noOfTickets = 3 userId = 1 TicketsOrdered ! noOfTickets = 3 ! userId = 1 noOfTickets = 3 userId = 1 time
  • 14. Event-sourced modelling TicketsOrdered TicketsOrdered Changing the price ConcertCreated ! artist = Aerosmith availableTickets = 100 price = 10 ... ! TicketsOrdered ! noOfTickets = 3 userId = 1 ! noOfTickets = 3 ! userId = 1 noOfTickets = 3 userId = 1 time
  • 15. Event-sourced modelling TicketsOrdered TicketsOrdered Changing the price ConcertCreated ! artist = Aerosmith availableTickets = 100 price = 10 ... ! PriceChanged ! price = 100 TicketsOrdered ! noOfTickets = 3 userId = 1 ! noOfTickets = 3 ! userId = 1 noOfTickets = 3 userId = 1 time
  • 16. Event-sourced modelling ConcertCreated ! artist = Aerosmith availableTickets = 100 price = 10 ... ! PriceChanged ! price = 100 TicketsOrdered TicketsOrdered ! noOfTickets = 3 userId = 1 TicketsOrdered ! noOfTickets = 3 ! userId = 1 noOfTickets = 3 userId = 1 Canceling an order time
  • 17. Event-sourced modelling ConcertCreated ! artist = Aerosmith availableTickets = 100 price = 10 ... ! PriceChanged ! price = 100 OrderCancelled ! userId = 1 TicketsOrdered TicketsOrdered ! noOfTickets = 3 userId = 1 TicketsOrdered ! noOfTickets = 3 ! userId = 1 noOfTickets = 3 userId = 1 Canceling an order time
  • 18. Event-sourced modelling ‣ Immutable events ‣ Append-only storage (scalable) ‣ Replay events: reconstruct historic state ‣ Events as audit mechanism ‣ Events as integration mechanism
  • 19. Event-sourcing: capture all changes to application state as a sequence of events Events: where from?
  • 20. Commands & Events Do something (active) It happened. Deal with it. (facts) Can be rejected (validation) Can be responded to
  • 21. Querying & event-sourcing How do you query a log?
  • 22. Querying & event-sourcing How do you query a log? Command Query Responsibility Segregation
  • 23. CQRS without ES Command Query UI/Client Service layer Database
  • 24. CQRS without ES Command Query UI/Client Service layer Database Command Query UI/Client Command Model Datastore Query Model(s) DaDtaastatosrtoere Datastore ?
  • 25. Event-sourced CQRS Command Query UI/Client Command Model Journal Query Model(s) DaDtaastatosrtoere Datastore Events
  • 26. Actors ‣ Mature and open source ‣ Scala & Java API ‣ Akka Cluster
  • 27. Actors "an island of consistency in a sea of concurrency" Actor ! ! ! mailbox state behavior async message send Process message: ‣ update state ‣ send messages ‣ change behavior Don't worry about concurrency
  • 28. Actors A good fit for event-sourcing? Actor ! ! ! mailbox state behavior mailbox is non-durable (lost messages) state is transient
  • 29. Actors Just store all incoming messages? Actor ! ! ! mailbox state behavior async message send store in journal Problems with command-sourcing: ‣ side-effects ‣ poisonous (failing) messages
  • 30. Persistence ‣ Experimental Akka module ‣ Scala & Java API ‣ Actor state persistence based on event-sourcing
  • 31. Persistent Actor PersistentActor actor-id ! ! state ! event async message send (command) ‣ Derive events from commands ‣ Store events ‣ Update state ‣ Perform side-effects event journal (actor-id)
  • 32. Persistent Actor PersistentActor actor-id ! ! state ! event ! Recover by replaying events, that update the state (no side-effects) ! event journal (actor-id)
  • 33. Persistent Actor ! case object Increment // command case object Incremented // event ! class CounterActor extends PersistentActor { def persistenceId = "counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } } ! val receiveRecover: Receive = { case Incremented => state += 1 } }
  • 34. Persistent Actor ! case object Increment // command case object Incremented // event ! class CounterActor extends PersistentActor { def persistenceId = "counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } } ! val receiveRecover: Receive = { case Incremented => state += 1 } }
  • 35. Persistent Actor ! case object Increment // command case object Incremented // event ! class CounterActor extends PersistentActor { def persistenceId = "counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } } ! val receiveRecover: Receive = { case Incremented => state += 1 } } async callback (but safe to close over state)
  • 36. Persistent Actor ! case object Increment // command case object Incremented // event ! class CounterActor extends PersistentActor { def persistenceId = "counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } } ! val receiveRecover: Receive = { case Incremented => state += 1 } }
  • 37. Persistent Actor ! case object Increment // command case object Incremented // event ! class CounterActor extends PersistentActor { def persistenceId = "counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } } ! val receiveRecover: Receive = { case Incremented => state += 1 } } Isn't recovery with lots of events slow?
  • 38. Snapshots class SnapshottingCounterActor extends PersistentActor { def persistenceId = "snapshotting-counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } case "takesnapshot" => saveSnapshot(state) } ! val receiveRecover: Receive = { case Incremented => state += 1 case SnapshotOffer(_, snapshotState: Int) => state = snapshotState } }
  • 39. Snapshots class SnapshottingCounterActor extends PersistentActor { def persistenceId = "snapshotting-counter" ! var state = 0 ! val receiveCommand: Receive = { case Increment => persist(Incremented) { evt => state += 1 println("incremented") } case "takesnapshot" => saveSnapshot(state) } ! val receiveRecover: Receive = { case Incremented => state += 1 case SnapshotOffer(_, snapshotState: Int) => state = snapshotState } }
  • 40. Journal & Snapshot Cassandra Cassandra Kafka Kafka MongoDB HBase DynamoDB MongoDB HBase MapDB JDBC JDBC Plugins:
  • 41. Plugins: Serialization Default: Java serialization Pluggable through Akka: ‣ Protobuf ‣ Kryo ‣ Avro ‣ Your own
  • 42. Persistent View Persistent Actor journal Persistent View Persistent View Views poll the journal ‣ Eventually consistent ‣ Polling configurable ‣ Actor may be inactive ‣ Views track single persistence-id ‣ Views can have own snapshots snapshot store other datastore
  • 43. Persistent View ! "The Database is a cache of a subset of the log" - Pat Helland Persistent Actor journal Persistent View Persistent View snapshot store other datastore
  • 44. Persistent View ! case object ComplexQuery class CounterView extends PersistentView { override def persistenceId: String = "counter" override def viewId: String = "counter-view" var queryState = 0 def receive: Receive = { case Incremented if isPersistent => { queryState = someVeryComplicatedCalculation(queryState) // Or update a document/graph/relational database } case ComplexQuery => { sender() ! queryState; // Or perform specialized query on datastore } } }
  • 45. Persistent View ! case object ComplexQuery class CounterView extends PersistentView { override def persistenceId: String = "counter" override def viewId: String = "counter-view" var queryState = 0 def receive: Receive = { case Incremented if isPersistent => { queryState = someVeryComplicatedCalculation(queryState) // Or update a document/graph/relational database } case ComplexQuery => { sender() ! queryState; // Or perform specialized query on datastore } } }
  • 46. Persistent View ! case object ComplexQuery class CounterView extends PersistentView { override def persistenceId: String = "counter" override def viewId: String = "counter-view" var queryState = 0 def receive: Receive = { case Incremented if isPersistent => { queryState = someVeryComplicatedCalculation(queryState) // Or update a document/graph/relational database } case ComplexQuery => { sender() ! queryState; // Or perform specialized query on datastore } } }
  • 47. Sell concert tickets ConcertActor ! ! price availableTickets startTime salesRecords ! Commands: CreateConcert BuyTickets ChangePrice AddCapacity journal ConcertHistoryView ! ! ! ! 60 45 30 15 0 100 50 0 $50 $75 $100 code @ bit.ly/akka-es
  • 48. Scaling out: Akka Cluster Single writer: persistent actor must be singleton, views may be anywhere Cluster node Cluster node Cluster node Persistent Persistent Actor id = "1" Actor id = "1" Persistent Actor id = "1" Persistent Actor id = "2" Persistent Actor id = "1" Persistent Actor id = "3" distributed journal
  • 49. Scaling out: Akka Cluster Single writer: persistent actor must be singleton, views may be anywhere How are persistent actors distributed over cluster? Cluster node Cluster node Cluster node Persistent Persistent Actor id = "1" Actor id = "1" Persistent Actor id = "1" Persistent Actor id = "2" Persistent Actor id = "1" Persistent Actor id = "3" distributed journal
  • 50. Scaling out: Akka Cluster Sharding: Coordinator assigns ShardRegions to nodes (consistent hashing) Actors in shard can be activated/passivated, rebalanced Cluster node Cluster node Cluster node Persistent Persistent Actor id = "1" Actor id = "1" Persistent Actor id = "1" Persistent Actor id = "2" Persistent Actor id = "1" Persistent Actor id = "3" Shard Region Shard Region Shard Region Coordinator distributed journal
  • 51. Scaling out: Sharding val idExtractor: ShardRegion.IdExtractor = { case cmd: Command => (cmd.concertId, cmd) } IdExtractor allows ShardRegion to route commands to actors
  • 52. Scaling out: Sharding val idExtractor: ShardRegion.IdExtractor = { case cmd: Command => (cmd.concertId, cmd) } IdExtractor allows ShardRegion to route commands to actors val shardResolver: ShardRegion.ShardResolver = msg => msg match { case cmd: Command => hash(cmd.concertId) } ShardResolver assigns new actors to shards
  • 53. Scaling out: Sharding val idExtractor: ShardRegion.IdExtractor = { case cmd: Command => (cmd.concertId, cmd) } IdExtractor allows ShardRegion to route commands to actors val shardResolver: ShardRegion.ShardResolver = msg => msg match { case cmd: Command => hash(cmd.concertId) } ShardResolver assigns new actors to shards ClusterSharding(system).start( typeName = "Concert", entryProps = Some(ConcertActor.props()), idExtractor = ConcertActor.idExtractor, shardResolver = ConcertActor.shardResolver) Initialize ClusterSharding extension
  • 54. Scaling out: Sharding val idExtractor: ShardRegion.IdExtractor = { case cmd: Command => (cmd.concertId, cmd) } IdExtractor allows ShardRegion to route commands to actors val shardResolver: ShardRegion.ShardResolver = msg => msg match { case cmd: Command => hash(cmd.concertId) } ShardResolver assigns new actors to shards ClusterSharding(system).start( typeName = "Concert", entryProps = Some(ConcertActor.props()), idExtractor = ConcertActor.idExtractor, shardResolver = ConcertActor.shardResolver) Initialize ClusterSharding extension val concertRegion: ActorRef = ClusterSharding(system).shardRegion("Concert") concertRegion ! BuyTickets(concertId = 123, user = "Sander", quantity = 1)
  • 56. DDD+CQRS+ES DDD: Domain Driven Design Fully consistent Fully consistent Aggregate ! Aggregate ! Eventual Consistency Root entity enteitnytity entity Root entity entity entity
  • 57. DDD+CQRS+ES DDD: Domain Driven Design Fully consistent Fully consistent Aggregate ! Aggregate ! Eventual Consistency Root entity enteitnytity entity Root entity entity entity Persistent Actor Persistent Actor Message passing
  • 58. DDD+CQRS+ES DDD: Domain Driven Design Fully consistent Fully consistent Aggregate ! Aggregate ! Eventual Consistency Akka Persistence is not a DDD/CQRS framework But it comes awfully close Root entity enteitnytity entity Root entity entity entity Persistent Actor Persistent Actor Message passing
  • 59. Designing aggregates Focus on events Structural representation(s) follow ERD
  • 60. Designing aggregates Focus on events Structural representation(s) follow ERD Size matters. Faster replay, less write contention Don't store derived info (use views)
  • 61. Designing aggregates Focus on events Structural representation(s) follow ERD Size matters. Faster replay, less write contention Don't store derived info (use views) With CQRS read-your-writes is not the default When you need this, model it in a single Aggregate
  • 62. Between aggregates ‣ Send commands to other aggregates by id ! ‣ No distributed transactions ‣ Use business level ack/nacks ‣ SendInvoice -> InvoiceSent/InvoiceCouldNotBeSent ‣ Compensating actions for failure ‣ No guaranteed delivery ‣ Alternative: AtLeastOnceDelivery
  • 63. Between systems System integration through event-sourcing topic 1 topic 2 derived Kafka Application Akka Persistence Spark Streaming External Application
  • 64. Designing commands ‣ Self-contained ‣ Unit of atomic change ‣ Granularity and intent
  • 65. Designing commands ‣ Self-contained ‣ Unit of atomic change ‣ Granularity and intent UpdateAddress street = ... city = ... vs ChangeStreet street = ... ChangeCity street = ...
  • 66. Designing commands ‣ Self-contained ‣ Unit of atomic change ‣ Granularity and intent UpdateAddress street = ... city = ... vs ChangeStreet street = ... ChangeCity street = ... Move street = ... city = ... vs
  • 68. Designing events CreateConcert ConcertCreated Past tense Irrefutable
  • 69. Designing events CreateConcert ConcertCreated Past tense Irrefutable TicketsBought newCapacity = 99
  • 70. Designing events CreateConcert ConcertCreated Past tense Irrefutable TicketsBought newCapacity = 99 TicketsBought quantity = 1 Delta-based No derived info
  • 71. Designing events CreateConcert ConcertCreated ConcertCreated Past tense Irrefutable TicketsBought newCapacity = 99 TicketsBought quantity = 1 Delta-based No derived info
  • 72. Designing events CreateConcert ConcertCreated ConcertCreated who/when/.. Add metadata to all events ConcertCreated Past tense Irrefutable TicketsBought newCapacity = 99 TicketsBought quantity = 1 Delta-based No derived info
  • 73. Versioning Actor logic: v1 and v2 event v2 event v2 event v1 event v1
  • 74. Versioning Actor logic: v1 and v2 event v2 event v2 event v1 event v1 Actor logic: v2 event v2 event v2 event v2 event v1 event v2 event v1
  • 75. Versioning Actor logic: v1 and v2 event v2 event v2 event v1 event v1 Actor logic: v2 event v2 event v2 event v2 event v1 event v2 event v1 Actor logic: v2 event v2 event v2 snapshot event v1 event v1
  • 76. Versioning Actor logic: v1 and v2 event v2 event v2 event v1 event v1 Actor logic: v2 event v2 event v2 event v2 event v1 event v2 event v1 Actor logic: v2 event v2 event v2 snapshot event v1 event v1 ‣ Be backwards compatible ‣ Avro/Protobuf ‣ Serializer can do translation ! ‣ Snapshot versioning: harder
  • 77. In conclusion Event-sourcing is... Powerful but unfamiliar
  • 78. In conclusion Event-sourcing is... Powerful but unfamiliar Combines well with UI/Client Command Model Journal Query Model DaDtaastatosrtoere Datastore Events DDD/CQRS
  • 79. In conclusion Event-sourcing is... Powerful but unfamiliar Combines well with UI/Client Command Model Journal Query Model DaDtaastatosrtoere Datastore Events DDD/CQRS Not a
  • 80. In conclusion Akka Actors & Akka Persistence A good fit for event-sourcing PersistentActor actor-id ! ! state ! async message send (command) event event journal (actor-id) Experimental, view improvements needed
  • 81. Thank you. ! code @ bit.ly/akka-es @Sander_Mak Luminis Technologies