112
DDDing with Akka Persistence Konrad 'ktoso' Malawski GeeCON 2014 @ Kraków, PL Konrad `@ktosopl` Malawski

DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

  • Upload
    others

  • View
    12

  • Download
    0

Embed Size (px)

Citation preview

Page 1: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

DDDing with Akka Persistence !

Konrad 'ktoso' Malawski GeeCON 2014 @ Kraków, PL

Konrad `@ktosopl` Malawski

Page 2: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Konrad `@ktosopl` Malawski

hAkker @

Page 3: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Konrad `@ktosopl` Malawski

typesafe.com geecon.org

Java.pl / KrakowScala.pl sckrk.com / meetup.com/Paper-Cup @ London

GDGKrakow.pl meetup.com/Lambda-Lounge-Krakow

hAkker @

Page 4: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Show of hands!

Page 5: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Show of hands!

Page 6: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Show of hands!

Page 7: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Show of hands!

Page 8: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

sourcing styles

Command Sourcing Event Sourcing

msg: DoThing

msg persisted before receive

imperative, “do the thing”

business logic change, can be reflected in reaction

no validation before persisting

Page 9: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

sourcing styles

Command Sourcing Event Sourcing

msg: DoThing msg: ThingDone

msg persisted before receive commands converted to events, must be manually persisted

imperative, “do the thing” past tense, “happened”

business logic change, can be reflected in reaction

business logic change, won’t change previous events

Processor validate, then maybe persist

Page 10: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Compared to “Good ol’ CRUD Model”

state

“Mutable Record”

state =

apply(es)

“Series of Events”

Page 11: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Actors

Page 12: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 0 !

!

Actor

An Actor that keeps count of messages it processed !

Let’s send 2 messages to it (it’s “commands”)

Page 13: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Actor

!!class Counter extends Actor {! var count = 0! def receive = {! case _ => count += 1! }!}

Page 14: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 0 !

!

Actor

Page 15: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 0 !

!

Actor

Page 16: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 1 !

!

Actor

crash!

Page 17: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Actor

crash!

Page 18: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Actor

restart

Page 19: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 0 !

!

Actor

restart

Page 20: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 0 !

!

Actor

restarted

Page 21: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 1 !

!

Actor

restarted

Page 22: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

count: 1 !

!wrong!

expected count == 2!

Actor

restarted

Page 23: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Consistency Boundary

Page 24: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Consistency Boundary equals Async Boundary

Page 25: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Boundaries

actor

actor

async

Page 26: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Boundaries

aggregate

aggregate

“eventual”

A.K.A. async

Page 27: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Business rules

aggregate

Any rule that spans AGGREGATES will not be expected to be up-to-date at all times. Through event processing, batch processing, or

other update mechanisms, other dependencies can be resolved within some specific time. [Evans, p. 128]

aggregate

consistentconsistent

eventually consistent

Page 28: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Let’s open the toolbox

Page 29: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

Akka  Persistence  ScalaDays  2014

Page 30: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

Processor & Eventsourced ProcessorReplaces:

in Akka 2.3.4+

Page 31: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

super quick domain modelling!

sealed trait Command!case class GiveMe(geeCoins: Int) extends Command!case class TakeMy(geeCoins: Int) extends Command

Commands - what others “tell” us; not persisted

case class Wallet(geeCoins: Int) {! def updated(diff: Int) = State(geeCoins + diff)!}

State - reflection of a series of events

sealed trait Event!case class BalanceChangedBy(geeCoins: Int) extends Event!

Events - reflect effects, past tense; persisted

Page 32: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

var state = S0 !

persistenceId = “a” !

PersistentActor

Command

!

!

Journal

Page 33: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

var state = S0 !

persistenceId = “a” !

!

!

Journal

Generate Events

Page 34: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

var state = S0 !

persistenceId = “a” !

!

!

Journal

Generate Events

E1

Page 35: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

ACK “persisted”

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

Page 36: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

“Apply” event

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Page 37: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Okey!

Page 38: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Okey!

Page 39: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

E1

Ok, he got my $.

Page 40: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

class BitCoinWallet extends PersistentActor {!! var state = Wallet(coins = 0)!! def updateState(e: Event): State = {! case BalanceChangedBy(coins) => state.updatedWith(coins)! }! ! // API:!! def receiveCommand = ??? // TODO!! def receiveRecover = ??? // TODO!!}!

Page 41: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

class BitCoinWallet extends PersistentActor {!! var state = Wallet(coins = 0)!! def updateState(e: Event): State = {! case BalanceChangedBy(coins) => state.updatedWith(coins)! }! ! // API:!! def receiveCommand = ??? // TODO!! def receiveRecover = ??? // TODO!!}!

Page 42: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persist(e) { e => }

Page 43: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

def receiveCommand = {!! case TakeMy(coins) =>! persist(BalanceChangedBy(coins)) { changed =>! state = updateState(changed) ! }!!!!!!!}

async callback

Page 44: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor: persist(){}

def receiveCommand = {!!!!!!! case GiveMe(coins) if coins <= state.coins =>! persist(BalanceChangedBy(-coins)) { changed =>! state = updateState(changed) ! sender() ! TakeMy(coins)! }!}

async callbackSafe to mutate

the Actor’s state

Page 45: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor

def receiveCommand = {!!!!!!! case GiveMe(coins) if coins <= state.coins =>! persist(BalanceChangedBy(-coins)) { changed =>! state = updateState(changed) ! sender() ! TakeMy(coins)! }!}

Safe to access sender here

Page 46: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persist(){} - Ordering guarantees

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

C1C2

C3

Page 47: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

!

!

Journal

E1

var state = S0 !

persistenceId = “a” !

C1C2

C3

Commands get “stashed” until processing C1’s events are acted upon.

persist(){} - Ordering guarantees

Page 48: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

!

!

Journal

var state = S0 !

persistenceId = “a” !

C1C2

C3 E1

E2

E2E1

events get applied in-order

persist(){} - Ordering guarantees

Page 49: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

C2

!

!

Journal

var state = S0 !

persistenceId = “a” !

C3 E1 E2

E2E1

and the cycle repeats

persist(){} - Ordering guarantees

Page 50: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(e) { e => }

Page 51: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(e) { e => } + defer(e) { e => }

Page 52: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

def receiveCommand = {!!!! case Mark(id) =>! sender() ! InitMarking! persistAsync(Marker) { m =>! // update state...! }!!!!!}

persistAsync

PersistentActor: persistAsync(){}

will NOT force stashing of commands

Page 53: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor: persistAsync(){}

def receiveCommand = {!!!! case Mark(id) =>! sender() ! InitMarking! persistAsync(Marker) { m =>! // update state...! }!! defer(Marked(id)) { marked =>! sender() ! marked! }!}

execute once all persistAsync handlers done

NOT persisted

Page 54: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

!

!

Journal

var state = S0 !

persistenceId = “a” !

C1C2

C3

Page 55: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

!

!

Journal

var state = S1 !

persistenceId = “a” !C2

C3

Page 56: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

!

!

Journal

var state = S2 !

persistenceId = “a” !

C3

Page 57: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

!

!

Journal

var state = S2 !

persistenceId = “a” !

C3

E1

E2

Page 58: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

var state = S2 !

persistenceId = “a” !

E1

Akka  Persistence  ScalaDays

!

!

Journal

E1

E2

C3

Page 59: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

E1

var state = S3 !

persistenceId = “a” !

E2

E1

E2

!

!

JournalAkka  Persistence  ScalaDays

E3

Page 60: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

persistAsync(){} - Ordering guarantees

E1

var state = S3 !

persistenceId = “a” !

E2

E1 E2

deferred handlers triggered

M1M2

!

!

JournalAkka  Persistence  ScalaDays

E3

Page 61: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Recovery

Akka  Persistence  ScalaDays

Page 62: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Eventsourced, recovery

/** MUST NOT SIDE-EFFECT! */!def receiveRecover = {! case replayedEvent: Event => ! state = updateState(replayedEvent)!}

re-using updateState, as seen in receiveCommand

Akka  Persistence  ScalaDays

Page 63: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Snapshots

Page 64: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Snapshots (in SnapshotStore)

Page 65: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Eventsourced, snapshots

def receiveCommand = {! case command: Command =>! saveSnapshot(state) // async!!}

/** MUST NOT SIDE-EFFECT! */!def receiveRecover = {! case SnapshotOffer(meta, snapshot: State) => ! this.state = state!! case replayedEvent: Event => ! updateState(replayedEvent)!}

snapshot!? how?

Page 66: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

…sum of states…

Snapshots

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

Page 67: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

state until [E8]

Snapshots

S8

!

!

Snapshot Store

snapshot!

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

Page 68: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

state until [E8]

Snapshots

S8

!

!

Snapshot Store

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

S8

crash!

Page 69: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Snapshots

!

!

Snapshot Store

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

S8

crash!

Page 70: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

“bring me up-to-date!”

Snapshots

!

!

Snapshot Store

!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

S8

restart!replay!

Page 71: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

“bring me up-to-date!”

Snapshots

!

!

Snapshot Store

S8

restart!replay!

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

Page 72: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

state until [E8]

Snapshots

!

!

Snapshot Store

S8

restart!replay!

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

Page 73: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

state until [E8]

Snapshots

!

!

Snapshot Store

S8

S8!

!

Journal

E1 E2 E3 E4

E5 E6 E7 E8

We could delete these!

Page 74: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

trait MySummer extends Processor {! var nums: List[Int]! var total: Int! ! def receive = {! case "snap" => saveSnapshot(total)! case SaveSnapshotSuccess(metadata) => // ...! case SaveSnapshotFailure(metadata, reason) => // ...! }!}!

Snapshots, save

Async!

Page 75: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

trait MySummer extends Processor {! var nums: List[Int]! var total: Int! ! def receive = {! case "snap" => saveSnapshot(total)! case SaveSnapshotSuccess(metadata) => // ...! case SaveSnapshotFailure(metadata, reason) => // ...! }!}!

Snapshots, success

final case class SnapshotMetadata(! processorId: String, sequenceNr: Long, ! timestamp: Long)

Page 76: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

trait MySummer extends Processor {! var nums: List[Int]! var total: Int! ! def receive = {! case "snap" => saveSnapshot(total)! case SaveSnapshotSuccess(metadata) => // ...! case SaveSnapshotFailure(metadata, reason) => // ...! }!}!

Snapshots, success

Page 77: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Snapshot Recovery

class Counter extends Processor {! var total = 0! ! def receive = {! case SnapshotOffer(metadata, snap: Int) => ! total = snap!! case Persistent(payload, sequenceNr) => // ...! }!}

Page 78: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Snapshots

Upsides

• Simple!

• Faster recovery (!)

• Allows to delete “older” events

• “known state at point in time”

Page 79: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Snapshots

Downsides

• More logic to write

• Maybe not needed if events replay “fast enough”

• Possibly “yet another database” to pick

• snapshots are different than events, may be big!

Page 80: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Views

Akka  Persistence  ScalaDays

Page 81: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Journal (DB)

!

!

!

Views

!Persistent

Actor !

persistenceId = “a” !

polling

Akka  Persistence  ScalaDays

Persistent View !

persistenceId = “a” !!

Page 82: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Journal (DB)

!

!

!

Views

!Persistent

Actor !

persistenceId = “a” !

polling

Persistent View !

persistenceId = “a” !!

polling

different ActorPath, same processorId

Akka  Persistence  ScalaDays

Persistent View !

persistenceId = “a” !!

Page 83: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

View

class DoublingCounterProcessor extends View {! var state = 0! override val processorId = "counter"!! def receive = {! case Persistent(payload, seqNr) =>! // “state += 2 * payload” !! }!}

subject to change!

Akka  Persistence  ScalaDays

Page 84: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Views, as Reactive Streams

Akka  Persistence  ScalaDays

Page 85: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

View, as ReactiveStream

// Imports ...!!import org.reactivestreams.Publisher!!import akka.stream._!import akka.stream.scaladsl.Flow!!import akka.persistence._!import akka.persistence.stream._!

val materializer = FlowMaterializer(MaterializerSettings())!

pull request by krasserm

early preview

Akka  Persistence  ScalaDays

Page 86: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

View, as ReactiveStream

// 1 producer and 2 consumers:!val p1: Publisher[Persistent] = PersistentFlow.! fromPersistenceId(“p-1").! toPublisher(materializer)!!Flow(p1).! foreach(p => println(s"subs-1: ${p.payload}”)).! consume(materializer)!!Flow(p1).! foreach(p => println(s"subs-2: ${p.payload}”)).! consume(materializer)

pull request by krasserm

early preview

Akka  Persistence  ScalaDays

Page 87: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

View, as ReactiveStream

// 2 producers (merged) and 1 consumer:!val p2: Publisher[Persistent] = PersistentFlow.! fromPersistenceId(“p-2").! toPublisher(materializer)!val p3: Publisher[Persistent] = PersistentFlow.! fromPersistenceId(“p-3").! toPublisher(materializer)!!Flow(p2).merge(p3). // triggers on “either”! foreach { p => println(s"subs-3: ${p.payload}") }.! consume(materializer)!

pull request by krasserm

early preview

Akka  Persistence  ScalaDays

Page 88: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Persistence + Cluster

Akka  Persistence  ScalaDays

Page 89: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Usage in a Cluster• distributed journal (http://akka.io/community/) • Cassandra • DynamoDB • HBase • Kafka • MongoDB • shared LevelDB journal for testing

Page 90: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Usage in a Cluster• single writer • cluster singleton • cluster sharding

Page 91: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Singleton

A B

C D

Page 92: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Singleton

AB

C

D

role: backend-1 role: backend-1

role: backend-2 role: backend-2

Page 93: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Sharding

A B

C D

Page 94: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Sharding

sender

id:17

region node-­‐1

coordinator

region node-­‐2

region node-­‐3

GetShardHome:17

id:17 ShardHome:17  -­‐>  node2

17  -­‐>  node2

Page 95: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Sharding

sender region node-­‐1

coordinator

region node-­‐2

region node-­‐3

id:17

id:17GetShardHome:17

ShardHome:17  -­‐>  node2

id:17

17  -­‐>  node2

17  -­‐>  node2

Page 96: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Sharding

17

sender region node-­‐1

coordinator

region node-­‐2

region node-­‐3

id:17

id:17

17  -­‐>  node2

17  -­‐>  node2

17  -­‐>  node2

Page 97: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Sharding

17

sender region node-­‐1

coordinator

region node-­‐2

region node-­‐3

17  -­‐>  node2

17  -­‐>  node2

17  -­‐>  node2

id:17

Page 98: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Cluster Sharding

17

sender region node-­‐1

coordinator

region node-­‐2

region node-­‐3

17  -­‐>  node2

17  -­‐>  node2

17  -­‐>  node2

id:17

Page 99: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Cluster Sharding

val idExtractor: ShardRegion.IdExtractor = { case cmd: Command => (cmd.postId, cmd) } ! val shardResolver: ShardRegion.ShardResolver = msg => msg match { case cmd: Command => (math.abs(cmd.postId.hashCode) % 100).toString }

ClusterSharding(system).start( typeName = BlogPost.shardName, entryProps = Some(BlogPost.props()), idExtractor = BlogPost.idExtractor, shardResolver = BlogPost.shardResolver)

val blogPostRegion: ActorRef = ClusterSharding(context.system).shardRegion(BlogPost.shardName) !val postId = UUID.randomUUID().toString blogPostRegion ! BlogPost.AddPost(postId, author, title)

Page 100: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Lost messages

sender destination

$

Page 101: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

At-least-once delivery - duplicates

sender destination

$

ok

$

$$

ok

Re-­‐send

Page 102: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

M2

At-least-once delivery - unordered

sender destination

M1

ok  1 ok  2

M2

ok  3

M3

M1M3M2

Re-­‐send

Page 103: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

M2

At-least-once delivery - crash

sender destination

M1

ok  1 ok  2

M2

ok  3

M3

1. Sent  M1  2. Sent  M2  3. Sent  M3  

M3

5.  M2  Confirmed  6.  M3  Confirmed

4.  M1  Confirmed

senderM1M2M3

Page 104: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

PersistentActor with AtLeastOnceDeliverycase class Msg(deliveryId: Long, s: String) case class Confirm(deliveryId: Long) sealed trait Evt case class MsgSent(s: String) extends Evt case class MsgConfirmed(deliveryId: Long) extends Evt

class Sender(destination: ActorPath) extends PersistentActor with AtLeastOnceDelivery { ! def receiveCommand: Receive = { case s: String => persist(MsgSent(s))(updateState) case Confirm(deliveryId) => persist(MsgConfirmed(deliveryId))(updateState) } ! def receiveRecover: Receive = { case evt: Evt => updateState(evt) } ! def updateState(evt: Evt): Unit = evt match { case MsgSent(s) => deliver(destination, deliveryId => Msg(deliveryId, s)) ! case MsgConfirmed(deliveryId) => confirmDelivery(deliveryId) } }

Page 105: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Try it now

Page 106: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Try it now() // !

typesafe.com/activator

akka-sample-persistence-scala !

!

https://github.com/hseeberger/akkamazing

Page 107: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Akka  Persistence  ScalaDays  2014

Next step• Documentation

• http://doc.akka.io/docs/akka/2.3.3/scala/persistence.html • http://doc.akka.io/docs/akka/2.3.3/java/persistence.html • http://doc.akka.io/docs/akka/2.3.3/contrib/cluster-sharding.html

• Typesafe Activator • https://typesafe.com/activator/template/akka-sample-persistence-scala • https://typesafe.com/activator/template/akka-sample-persistence-java • http://typesafe.com/activator/template/akka-cluster-sharding-scala

• Mailing list • http://groups.google.com/group/akka-user

• Migration guide from Eventsourced • http://doc.akka.io/docs/akka/2.3.3/project/migration-guide-

eventsourced-2.3.x.html

Page 108: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Links

• Official docs: http://doc.akka.io/docs/akka/2.3.0/scala/persistence.html

• Patrik’s Slides & Webinar: http://www.slideshare.net/patriknw/akka-persistence-webinar

• Papers:

• Sagas http://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf

• Life beyond Distributed Transactions: http://www-db.cs.wisc.edu/cidr/cidr2007/papers/cidr07p15.pdf

• Pics:

• http://misaspuppy.deviantart.com/art/Messenger-s-Cutie-Mark-A-Flying-Envelope-291040459

Page 109: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

Mailing List

groups.google.com/forum/#!forum/akka-user

Page 111: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

ktoso @ typesafe.com twitter: ktosopl github: ktoso blog: project13.pl team blog: letitcrash.com

ScalaCamp #6 2014 @ Kraków, PL

akka-user @ google groups

!

Dzięki! Thanks! ありがとう!

Page 112: DDDing with Akka Persistence - Scalacampscalacamp.pl/data/akka-persistence-scalacamp.pdf · DDDing with Akka Persistence!! Konrad 'ktoso' Malawski! GeeCON 2014 @ Kraków, PL Konrad

©Typesafe 2014 – All Rights Reserved