@michaltomanski
class UserService {
createUser(User user): Unit
getUser(long id): User
}
class UserWriteService {
createUser(User user): Unit
}
class UserReadService {
getUser(long id): User
}
DeactivateUser(id = 1)
Is the user with id=1 active?
UserDeactivated(id = 1)
UserDeactivated(id = 1) goes to DB
isActive = false
Rare
Show to the user his:
Show to the user other people's:
Average of 5: 16, (20), 18, 18, (15)
= (16 + 18 + 18) /3
class Speedcuber extends Actor {
var times = Nil
def receive = {
case AddTime(time: Long) => times :+ time
}
}
actor ! AddTime(500)
class Speedcuber extends PersistentActor {
var times = Nil
override def receiveCommand: Receive = {
case addTime: AddTime =>
persist(addTime) { event =>
times = times :+ event.time
}
}
override def receiveRecover: Receive = {
case addTime: AddTime => times = times :+ event.time
case RecoveryCompleted => println("Events recovery completed")
}
override def persistenceId: String = "speedcuber"
}
Persistent Actor
Journal (Cassandra)
akka.persistence.journal.plugin = "cassandra-journal"
akka.persistence.snapshot-store.plugin = "cassandra-snapshot-store"
Akka persistence query
Postgresql
val s = readJournal.eventsByTag("Speedcuber")
val s = readJournal.eventsByTag("Speedcuber", state.offset)
s.mapAsync(1)(handleEvent).runWith(Sink.foreach(offset => self ! SaveOffset(offset)))
def handleEvent = {
case EventEnvelope(offset, _, _, event: BestAvgChanged) =>
viewBuilder.upsertBestAvgView(BestAvg(event.user, event.millis)).map(_ => offset)
val s = readJournal.eventsByTag("Speedcuber", state.offset)
val s = readJournal.eventsByTag("Speedcuber", state.offset)
s.mapAsync(1)(handleEvent)
val s = readJournal.eventsByTag("Speedcuber", state.offset)
s.mapAsync(1)(handleEvent).runWith(Sink.foreach(offset => self ! SaveOffset(offset)))
The oldest node
@michaltomanski
slides.com/michaltomanski/cqrs
github.com/michaltomanski/cqrs-demo
vote.scalaua.com
¯\_(ツ)_/¯
Node 1
Node 2
event-adapters = {
speedcuber = "com.mtomanski.timer.infrastructure
.akka.adapter.SpeedcuberEventsTaggingAdapter"
}
event-adapter-bindings = {
"com.mtomanski.timer.domain.model.Speedcuber" = [speedcuber]
}
class SpeedcuberEventsTaggingAdapter extends WriteEventAdapter {
override def toJournal(event: Any): Any = Tagged(event, Set("Speedcuber"))
...
}