resilient applications with akka persistence - scaladays 2014
DESCRIPTION
In this presentation you will learn how to leverage the features introduced in Akka Persistence: opt-in at-least-once delivery semantics between actors and the ability to recover application state after a crash. Both are implemented by storing immutable facts in a persisted append-only log. We will show you how to create persistent actors using command and event sourcing, replicate events with reliable communication, scale out and improve resilience with clustering.TRANSCRIPT
![Page 1: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/1.jpg)
Resilient Applications with Akka Persistence
Patrik Nordwall@patriknw
Konrad Malawski@ktosopl
Björn Antonsson@bantonsson
![Page 2: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/2.jpg)
Reactive Applications
Akka Persistence ScalaDays 2014
![Page 3: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/3.jpg)
Resilient
• Embrace Failure • Failure is a normal part of the application lifecycle
• Self Heal • Failure is detected, isolated, and managed
Akka Persistence ScalaDays 2014
![Page 4: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/4.jpg)
The Naïve Way
• Write State to Database
• Transactions Everywhere
• Problem Solved?
• Not Scalable, Responsive, Event-Driven!
Akka Persistence ScalaDays 2014
![Page 5: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/5.jpg)
Command and Event Sourcing
![Page 6: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/6.jpg)
Command and Event Sourcing
• State is the sum of Events
• Events are persisted to Store
• Append only
• Scales well
Akka Persistence ScalaDays 2014
![Page 7: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/7.jpg)
Command v.s. Event
• Command
• What someone wants me to do
• Can be rejected
• Event
• Something that has already happened
• An immutable fact
Akka Persistence ScalaDays 2014
![Page 8: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/8.jpg)
Commands can Generate Events
• If I accept a Command and change State
• Persist Event to Store
• If I crash
• Replay Events to recover State
Akka Persistence ScalaDays 2014
![Page 9: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/9.jpg)
Persist All Commands?
• If I crash on a Command
• I will likely crash during recovery
• Like the Army
• Don't question orders
• Repeat until success
Akka Persistence ScalaDays 2014
![Page 10: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/10.jpg)
Only Persist Events
• Only accepted Commands generate Events
• No surprises during recovery
• Like a dieting method
• You are what you eat
Akka Persistence ScalaDays 2014
![Page 11: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/11.jpg)
Achievement Unlocked?
• Resilient
• State is recoverable
• Scalable
• Append only writes
• Something Missing?
• Queries
Akka Persistence ScalaDays 2014
![Page 12: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/12.jpg)
CQRSCommand Query Responsibility Segregation
![Page 13: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/13.jpg)
CQRS
• Separate Models
• Command Model
• Optimized for command processing
• Query Model
• Optimized data presentation
Akka Persistence ScalaDays 2014
![Page 14: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/14.jpg)
Query Model from Events
• Source the Events
• Pick what fits
• In Memory
• SQL Database
• Graph Database
• Key Value Store
Akka Persistence ScalaDays 2014
![Page 15: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/15.jpg)
Akka Persistence ScalaDays 2014
Client
Service
Query Model
Command Store
Query Store
Command Model
![Page 16: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/16.jpg)
PersistentActor
Akka Persistence ScalaDays 2014
![Page 17: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/17.jpg)
PersistentActor
Processor & Eventsourced ProcessorReplaces:
in Akka 2.3.4+
![Page 18: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/18.jpg)
super quick domain modelling!
sealed trait Command!case class GiveMe(coins: Int) extends Command!case class TakeMy(coins: Int) extends Command
Commands - what others “tell” us; not persisted
case class Wallet(coins: Int) {! def updated(diff: Int) = State(coins + diff)!}
State - reflection of a series of events
sealed trait Event!case class BalanceChangedBy(coins: Int) extends Event!
Events - reflect effects, past tense; persisted
![Page 19: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/19.jpg)
var state = S0 !
def processorId = “a” !
PersistentActor
Command
!
!
Journal
![Page 20: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/20.jpg)
PersistentActor
var state = S0 !
def processorId = “a” !
!
!
Journal
Generate Events
![Page 21: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/21.jpg)
PersistentActor
var state = S0 !
def processorId = “a” !
!
!
Journal
Generate Events
E1
![Page 22: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/22.jpg)
PersistentActor
ACK “persisted”
!
!
Journal
E1
var state = S0 !
def processorId = “a” !
![Page 23: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/23.jpg)
PersistentActor
“Apply” event
!
!
Journal
E1
var state = S1 !
def processorId = “a” !
E1
![Page 24: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/24.jpg)
PersistentActor
!
!
Journal
E1
var state = S1 !
def processorId = “a” !
E1
Okey!
![Page 25: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/25.jpg)
PersistentActor
!
!
Journal
E1
var state = S1 !
def processorId = “a” !
E1
Okey!
![Page 26: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/26.jpg)
PersistentActor
!
!
Journal
E1
var state = S1 !
def processorId = “a” !
E1
Ok, he got my $.
![Page 27: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/27.jpg)
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 28: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/28.jpg)
persist(e) { e => }
![Page 29: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/29.jpg)
PersistentActor
def receiveCommand = {!! case TakeMy(coins) =>! persist(BalanceChangedBy(coins)) { changed =>! state = updateState(changed) ! }!!!!!!!}
async callback
![Page 30: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/30.jpg)
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 31: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/31.jpg)
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 32: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/32.jpg)
persist(){} - Ordering guarantees
!
!
Journal
E1
var state = S0 !
def processorId = “a” !
C1C2
C3
![Page 33: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/33.jpg)
!
!
Journal
E1
var state = S0 !
def processorId = “a” !
C1C2
C3
Commands get “stashed” until processing C1’s events are acted upon.
persist(){} - Ordering guarantees
![Page 34: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/34.jpg)
!
!
Journal
var state = S0 !
def processorId = “a” !
C1C2
C3 E1
E2
E2E1
events get applied in-order
persist(){} - Ordering guarantees
![Page 35: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/35.jpg)
C2
!
!
Journal
var state = S0 !
def processorId = “a” !
C3 E1 E2
E2E1
and the cycle repeats
persist(){} - Ordering guarantees
![Page 36: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/36.jpg)
persistAsync(e) { e => }
![Page 37: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/37.jpg)
persistAsync(e) { e => } + defer(e) { e => }
![Page 38: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/38.jpg)
def receiveCommand = {!!!! case Mark(id) =>! sender() ! InitMarking! persistAsync(Marker) { m =>! // update state...! }!!!!!}
persistAsync
PersistentActor: persistAsync(){}
will NOT force stashing of commands
![Page 39: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/39.jpg)
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 40: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/40.jpg)
persistAsync(){} - Ordering guarantees
!
!
Journal
var state = S0 !
def processorId = “a” !
C1C2
C3
![Page 41: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/41.jpg)
persistAsync(){} - Ordering guarantees
!
!
Journal
var state = S0 !
def processorId = “a” !C2
C3
![Page 42: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/42.jpg)
persistAsync(){} - Ordering guarantees
!
!
Journal
var state = S0 !
def processorId = “a” !
C3
![Page 43: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/43.jpg)
persistAsync(){} - Ordering guarantees
!
!
Journal
var state = S0 !
def processorId = “a” !
C3
E1
E2
![Page 44: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/44.jpg)
persistAsync(){} - Ordering guarantees
var state = S0 !
def processorId = “a” !
C3
E1
Akka Persistence ScalaDays
!
!
Journal
E1
E2
![Page 45: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/45.jpg)
persistAsync(){} - Ordering guarantees
E1
var state = S1 !
def processorId = “a” !
E2
E1
E2
!
!
JournalAkka Persistence ScalaDays
E2
E3E1
![Page 46: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/46.jpg)
persistAsync(){} - Ordering guarantees
E1
var state = S2 !
def processorId = “a” !
E2
E1 E2
deferred handlers triggered
M1M2
!
!
JournalAkka Persistence ScalaDays
E2
E3E1
![Page 47: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/47.jpg)
Recovery
Akka Persistence ScalaDays
![Page 48: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/48.jpg)
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 49: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/49.jpg)
Views
Akka Persistence ScalaDays
![Page 50: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/50.jpg)
Journal (DB)
!
!
!
Views
!Processor
!def processorId = “a”
!
polling
Akka Persistence ScalaDays
!View
!def processorId = “a”
!!!
![Page 51: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/51.jpg)
Journal (DB)
!
!
!
Views
!Processor
!def processorId = “a”
!
polling
!View
!def processorId = “a”
!!!
polling
different ActorPath, same processorId
Akka Persistence ScalaDays
!View
!def processorId = “a”
!!!
![Page 52: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/52.jpg)
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 53: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/53.jpg)
Views, as Reactive Streams
Akka Persistence ScalaDays
![Page 54: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/54.jpg)
View, as ReactiveStream
// Imports ...!!import org.reactivestreams.api.Producer!!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 55: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/55.jpg)
View, as ReactiveStream
// 1 producer and 2 consumers:!val p1: Producer[Persistent] = PersistentFlow.! fromProcessor(“processor-1").! toProducer(materializer)!!Flow(p1).! foreach(p => println(s"consumer-1: ${p.payload}”)).! consume(materializer)!!Flow(p1).! foreach(p => println(s"consumer-2: ${p.payload}”)).! consume(materializer)
pull request by krasserm
early preview
Akka Persistence ScalaDays
![Page 56: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/56.jpg)
View, as ReactiveStream
// 2 producers (merged) and 1 consumer:!val p2: Producer[Persistent] = PersistentFlow.! fromProcessor(“processor-2").! toProducer(materializer)!val p3: Producer[Persistent] = PersistentFlow.! fromProcessor(“processor-3").! toProducer(materializer)!!Flow(p2).merge(p3). // triggers on “either”! foreach { p => println(s"consumer-3: ${p.payload}") }.! consume(materializer)!
pull request by krasserm
early preview
Akka Persistence ScalaDays
![Page 57: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/57.jpg)
Akka Persistence ScalaDays 2014
Usage in a Cluster
• distributed journal (http://akka.io/community/)
• Cassandra
• DynamoDB
• HBase
• MongoDB
• shared LevelDB journal for testing
• single writer
• cluster singleton
• cluster sharding
![Page 58: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/58.jpg)
Akka Persistence ScalaDays 2014
Cluster Singleton
AB
C D
![Page 59: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/59.jpg)
Akka Persistence ScalaDays 2014
Cluster Singleton
AB
C
D
role: backend-1 role: backend-1
role: backend-2 role: backend-2
![Page 60: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/60.jpg)
Akka Persistence ScalaDays 2014
Cluster Sharding
A B
C D
![Page 61: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/61.jpg)
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 62: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/62.jpg)
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 63: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/63.jpg)
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 64: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/64.jpg)
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 65: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/65.jpg)
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 66: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/66.jpg)
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 67: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/67.jpg)
Akka Persistence ScalaDays 2014
Lost messages
sender destination
$
![Page 68: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/68.jpg)
Akka Persistence ScalaDays 2014
At-least-once delivery - duplicates
sender destination
$
ok
$
$$
ok
Re-‐send
![Page 69: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/69.jpg)
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 70: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/70.jpg)
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
senderM1M2
M3
![Page 71: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/71.jpg)
PersistentActor with AtLeastOnceDelivery
case 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 72: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/72.jpg)
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 73: Resilient Applications with Akka Persistence - Scaladays 2014](https://reader034.vdocuments.net/reader034/viewer/2022051608/53fdc60a8d7f72a81c8b4afa/html5/thumbnails/73.jpg)
©Typesafe 2014 – All Rights Reserved