CQRS and Event Sourcing with Akka, Cassandra and RabbitMQ
-
Upload
miel-donkers -
Category
Software
-
view
747 -
download
3
Transcript of CQRS and Event Sourcing with Akka, Cassandra and RabbitMQ
2 . 6
Storing dataSimple approach
Single databaseNormalized tables for write-side dataViews for denormalizing dataKeep queries simple
2 . 9
What is ESEvent SourcingEvent describes the state change of aggregateEvent is saved in event storeEvents can be replayed to re-create the current state.
2 . 15
ConsistencyKey feature for the Event StoreWithout transactions, much work needed to make asreliableVersioning / timestampsEventual consistency
2 . 16
Error HandlingDistinguish between business faults and errors.
Errors can be re-tried.Business faults should have pre-determinedreaction.
2 . 17
Other disadvantagesMany moving parts, makes it hard to debug thesystem as a wholeCQRS not for every bounded context
2 . 19
AdvantagesTask-based UIRead and write side can be optimized separatelyDebug in local environmentSmall components which are easy to update / fix
2 . 22
User Repositoryprivate var users = Set.empty[User]
override def receiveCommand: Receive = { case GetUsers => sender() ! users case AddUser(name) if users.exists(_.name == name) => sender() ! UserExists(name) case AddUser(user) => persist(user) { persistedUser => receiveRecover(persistedUser) sender() ! UserAdded(persistedUser) } }
override def receiveRecover: Receive = { case user: User => users += user }
2 . 23
Event Senderprivate var unconfirmed = immutable.SortedMap.empty[Long, ActorPath]
override def receive: Receive = { case Msg(deliveryId, user) => unconfirmed = unconfirmed.updated(deliveryId, sender().path) val headersMap = Map(RabbitMQConstants.MESSAGE_ID -> deliveryId, RabbitMQConstants.CORRELATIONID -> deliveryId) camelSender ! CamelMessage(user.asJson.noSpaces, headersMap)
case CamelMessage(_, headers) => val deliveryId: Long = headers.getOrElse(RabbitMQConstants.MESSAGE_ID, - unconfirmed.get(deliveryId).foreach( senderActor => { unconfirmed -= deliveryId context.actorSelection(senderActor) ! Confirm(deliveryId) })
case Status.Failure(ex) =>
2 . 24
Event Receiveroverride def receive: Receive = { case msg: CamelMessage => val body: Xor[Error, User] = decode[User](msg.bodyAs[String]) body.fold({ error => sender() ! Failure(error) }, { user => sender() ! Ack }) case _ => log.warning("Unexpected event received") }
2 . 25
LinksMartin Fowler - CQRSMicrosoft - CQRS JourneyAkkaHeiko Seeberger - Reactive Flows Demo