SlideShare a Scribd company logo
1 of 36
Download to read offline
Taming Distribution:
Formal Protocols
for Akka Typed
Dr. Roland Kuhn
@rolandkuhn — CTO of Actyx
Distribution
=
Concurrency + Partial Failure
Distribution
=
Concurrency + Partial Failure
Distribution
=
Concurrency + Partial Failure
Actors model distribution.
Concurrency implies Nondeterminism.
Distribution implies more Nondeterminism.
Concurrency implies Nondeterminism.
Distribution implies more Nondeterminism.
Causality restricts Nondeterminism.
Some causality comes naturally.
Akka Typed Receptionist API
trait ServiceKey[T]
sealed trait Command
final case class Register[T](key: ServiceKey[T], address: ActorRef[T],
replyTo: ActorRef[Registered[T]]) extends Command
final case class Registered[T](key: ServiceKey[T], address: ActorRef[T])
final case class Find[T](key: ServiceKey[T], replyTo: ActorRef[Listing[T]]) extends Command
final case class Listing[T](key: ServiceKey[T], addresses: Set[ActorRef[T]])
… with Unregister support
trait ServiceKey[T]
sealed trait Command
final case class Register[T](key: ServiceKey[T], address: ActorRef[T],
replyTo: ActorRef[Registered[T]]) extends Command
final case class Registered[T](key: ServiceKey[T], address: ActorRef[T], handle: ActorRef[Unregister])
final case class Unregister(replyTo: ActorRef[Unregistered])
final case class Unregistered()
final case class Find[T](key: ServiceKey[T], replyTo: ActorRef[Listing[T]]) extends Command
final case class Listing[T](key: ServiceKey[T], addresses: Set[ActorRef[T]])
For everything that is not fixed by causality
coordination is needed.
Static knowledge avoids coordination.
Cluster Receptionist
Cluster Receptionist
• use FQCN of service keys as known identifier
Cluster Receptionist
• use FQCN of service keys as known identifier
• local resolution establishes static type-safety
Cluster Receptionist
• use FQCN of service keys as known identifier
• local resolution establishes static type-safety
• CRDT map from keys to sets of ActorRefs
Natural causality is not enough!
Example: payment with audit
Messages for a payment system
case object AuditService extends ServiceKey[LogActivity]
case class LogActivity(who: ActorRef[Nothing], what: String,
id: Long, replyTo: ActorRef[ActivityLogged])
case class ActivityLogged(who: ActorRef[Nothing], id: Long)
Messages for a payment system
case object AuditService extends ServiceKey[LogActivity]
case class LogActivity(who: ActorRef[Nothing], what: String,
id: Long, replyTo: ActorRef[ActivityLogged])
case class ActivityLogged(who: ActorRef[Nothing], id: Long)
sealed trait PaymentService
case class Authorize(payer: URI, amount: BigDecimal, id: UUID, replyTo: ActorRef[PaymentResult])
extends PaymentService
case class Capture(id: UUID, amount: BigDecimal, replyTo: ActorRef[PaymentResult])
extends PaymentService
case class Void(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService
case class Refund(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService
Messages for a payment system
case object AuditService extends ServiceKey[LogActivity]
case class LogActivity(who: ActorRef[Nothing], what: String,
id: Long, replyTo: ActorRef[ActivityLogged])
case class ActivityLogged(who: ActorRef[Nothing], id: Long)
sealed trait PaymentService
case class Authorize(payer: URI, amount: BigDecimal, id: UUID, replyTo: ActorRef[PaymentResult])
extends PaymentService
case class Capture(id: UUID, amount: BigDecimal, replyTo: ActorRef[PaymentResult])
extends PaymentService
case class Void(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService
case class Refund(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService
sealed trait PaymentResult
case class PaymentSuccess(id: UUID) extends PaymentResult
case class PaymentRejected(id: UUID, reason: String) extends PaymentResult
case class IdUnkwown(id: UUID) extends PaymentResult
Akka Typed crash course
case class Greet(whom: String)
class Greeter extends akka.actor.Actor {
def receive = {
case Greet(whom) => println(s"Hello $whom!")
}
}
Akka Typed crash course
case class Greet(whom: String)
class Greeter extends akka.actor.Actor {
def receive = {
case Greet(whom) => println(s"Hello $whom!")
}
}
object Greeter {
import akka.typed.scaladsl.Actor
val behavior =
Actor.immutable[Greet] { (ctx, greet) =>
println(s"Hello ${greet.whom}!")
Actor.same
}
}
First actor: do the audit
sealed trait Msg
private case object AuditDone extends Msg
private case object PaymentDone extends Msg
private def doAudit(audit: ActorRef[LogActivity], who: ActorRef[AuditDone.type], msg: String) =
Actor.deferred[ActivityLogged] { ctx =>
val id = Random.nextLong()
audit ! LogActivity(who, msg, id, ctx.self)
ctx.schedule(3.seconds, ctx.self, ActivityLogged(null, 0L))
Actor.immutable { (ctx, msg) =>
if (msg.who == null) throw new TimeoutException
else if (msg.id != id) throw new IllegalStateException
else {
who ! AuditDone
Actor.stopped
}
}
}
Second actor: do the payment
private def doPayment(from: URI, amount: BigDecimal, payments: ActorRef[PaymentService],
replyTo: ActorRef[PaymentDone.type]) =
Actor.deferred[PaymentResult] { ctx =>
val uuid = UUID.randomUUID()
payments ! Authorize(from, amount, uuid, ctx.self)
ctx.schedule(3.seconds, ctx.self, IdUnkwown(null))
Actor.immutable {
case (ctx, PaymentSuccess(`uuid`)) =>
payments ! Capture(uuid, amount, ctx.self)
Actor.immutable {
case (ctx, PaymentSuccess(`uuid`)) =>
replyTo ! PaymentDone
Actor.stopped
}
// otherwise die with MatchError
}
}
Third actor: orchestration of the process
def getMoney[R](from: URI, amount: BigDecimal,
payments: ActorRef[PaymentService], audit: ActorRef[LogActivity],
replyTo: ActorRef[R], msg: R) =
Actor.deferred[Msg] { ctx =>
ctx.watch(ctx.spawn(doAudit(audit, ctx.self, "starting payment"), "preAudit"))
Actor.immutable[Msg] {
case (ctx, AuditDone) =>
ctx.watch(ctx.spawn(doPayment(from, amount, payments, ctx.self), "payment"))
Actor.immutable[Msg] {
case (ctx, PaymentDone) =>
ctx.watch(ctx.spawn(doAudit(audit, ctx.self, "payment finished"), "postAudit"))
Actor.immutable[Msg] {
case (ctx, AuditDone) =>
replyTo ! msg
Actor.stopped
}
} onSignal terminateUponChildFailure
} onSignal terminateUponChildFailure
}
code can employ knowledge in wrong order
or
existing knowledge is not used at all
What if we prescribe effects and their order?
Which steps shall be done?
• send audit log, get confirmation for that
• send Authorize request, get confirmation
• send Capture request, get confirmation
• send audit log, get confirmation
Akka Typed Session: protocol definition
object GetMoneyProtocol extends Protocol {
type Session = //
Send[LogActivity] :: // preAudit
Read[ActivityLogged] :: //
Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate
Send[Authorize] :: // do payment
Read[PaymentResult] :: //
Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate
Send[Capture] :: //
Read[PaymentResult] :: //
Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate
Send[LogActivity] :: // postAudit
Read[ActivityLogged] :: //
Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate
_0
}
First process: do the audit
private def doAudit(audit: ActorRef[LogActivity], who: ActorRef[Nothing], msg: String) =
OpDSL[ActivityLogged] { implicit opDSL =>
val id = Random.nextLong()
for {
self <- opProcessSelf
_ <- opSend(audit, LogActivity(who, msg, id, self))
ActivityLogged(`who`, `id`) <- opRead
} yield Done
}.withTimeout(3.seconds)
/*
* the return type is
* Process[ActivityLogged, Done,
* Send[LogActivity] :: Read[ActivityLogged] ::
* Choice[(Halt :: _0) :+: _0 :+: CNil] :: _0]
*/
Second process: do the payment
private def doPayment(from: URI, amount: BigDecimal, payments: ActorRef[PaymentService]) =
OpDSL[PaymentResult] { implicit opDSL =>
val uuid = UUID.randomUUID()
for {
self <- opProcessSelf
_ <- opSend(payments, Authorize(from, amount, uuid, self))
PaymentSuccess(`uuid`) <- opRead
_ <- opSend(payments, Capture(uuid, amount, self))
PaymentSuccess(`uuid`) <- opRead
} yield Done
}.withTimeout(3.seconds)
/*
* the return type is
* Process[PaymentResult, Done,
* Send[Authorize] :: Read[PaymentResult] ::
* Choice[(Halt :: _0) :+: _0 :+: CNil] ::
* Send[Capture] :: Read[PaymentResult] ::
* Choice[(Halt :: _0) :+: _0 :+: CNil] :: _0]
*/
Third process: orchestrate and verify
// this useful process is provided by the Session DSL and talks to the Receptionist
def getService[T](key: ServiceKey[T]): Operation[Listing[T], ActorRef[T], _0]
def getMoney[R](from: URI, amount: BigDecimal,
payments: ActorRef[PaymentService],
replyTo: ActorRef[R], msg: R) =
OpDSL[Nothing] { implicit opDSL =>
for {
self <- opProcessSelf
audit <- opCall(getService(AuditService) .named("getAuditService"))
_ <- opCall(doAudit(audit, self, "starting payment").named("preAudit"))
_ <- opCall(doPayment(from, amount, payments) .named("payment"))
_ <- opCall(doAudit(audit, self, "payment finished").named("postAudit"))
} yield replyTo ! msg
}
Third process: orchestrate and verify
// this useful process is provided by the Session DSL and talks to the Receptionist
def getService[T](key: ServiceKey[T]): Operation[Listing[T], ActorRef[T], _0]
def getMoney[R](from: URI, amount: BigDecimal,
payments: ActorRef[PaymentService],
replyTo: ActorRef[R], msg: R) =
OpDSL[Nothing] { implicit opDSL =>
for {
self <- opProcessSelf
audit <- opCall(getService(AuditService) .named("getAuditService"))
_ <- opCall(doAudit(audit, self, "starting payment").named("preAudit"))
_ <- opCall(doPayment(from, amount, payments) .named("payment"))
_ <- opCall(doAudit(audit, self, "payment finished").named("postAudit"))
} yield replyTo ! msg
}
// compile-time verification (TODO: should be a macro)
private def verify = E.vetExternalProtocol(GetMoneyProtocol, getMoney(???, ???, ???, ???, ???))
Conclusion:
There is a lot on the table,
get involved!
https://github.com/rkuhn/akka-typed-session

More Related Content

What's hot

VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
Darwin Durand
 
Declaring friend function with inline code
Declaring friend function with inline codeDeclaring friend function with inline code
Declaring friend function with inline code
Rajeev Sharan
 
c++ program for Railway reservation
c++ program for Railway reservationc++ program for Railway reservation
c++ program for Railway reservation
Swarup Kumar Boro
 

What's hot (19)

VISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLEVISUALIZAR REGISTROS EN UN JTABLE
VISUALIZAR REGISTROS EN UN JTABLE
 
Smart Contract programming 101 with Solidity #PizzaHackathon
Smart Contract programming 101 with Solidity #PizzaHackathonSmart Contract programming 101 with Solidity #PizzaHackathon
Smart Contract programming 101 with Solidity #PizzaHackathon
 
Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)Mutation testing: Too good to be true? (4Developers)
Mutation testing: Too good to be true? (4Developers)
 
Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)Mutation testing: Too good to be true? (Devoxx)
Mutation testing: Too good to be true? (Devoxx)
 
INSERCION DE REGISTROS DESDE VISUAL.NET A UNA BD DE SQL SERVER
INSERCION DE REGISTROS DESDE VISUAL.NET A UNA BD DE SQL SERVERINSERCION DE REGISTROS DESDE VISUAL.NET A UNA BD DE SQL SERVER
INSERCION DE REGISTROS DESDE VISUAL.NET A UNA BD DE SQL SERVER
 
Ss
SsSs
Ss
 
Voce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu CodigoVoce Tem Orgulho Do Seu Codigo
Voce Tem Orgulho Do Seu Codigo
 
Hands on with smart contracts 2. Presentation for the Blockchain Applications...
Hands on with smart contracts 2. Presentation for the Blockchain Applications...Hands on with smart contracts 2. Presentation for the Blockchain Applications...
Hands on with smart contracts 2. Presentation for the Blockchain Applications...
 
Rxjs vienna
Rxjs viennaRxjs vienna
Rxjs vienna
 
Dex and Uniswap
Dex and UniswapDex and Uniswap
Dex and Uniswap
 
Using Change Streams to Keep Up with Your Data
Using Change Streams to Keep Up with Your DataUsing Change Streams to Keep Up with Your Data
Using Change Streams to Keep Up with Your Data
 
Declaring friend function with inline code
Declaring friend function with inline codeDeclaring friend function with inline code
Declaring friend function with inline code
 
Rxjs swetugg
Rxjs swetuggRxjs swetugg
Rxjs swetugg
 
Source Code for Dpilot
Source Code for Dpilot Source Code for Dpilot
Source Code for Dpilot
 
Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots Dpilot Source Code With ScreenShots
Dpilot Source Code With ScreenShots
 
The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196The Ring programming language version 1.7 book - Part 16 of 196
The Ring programming language version 1.7 book - Part 16 of 196
 
The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189The Ring programming language version 1.6 book - Part 15 of 189
The Ring programming language version 1.6 book - Part 15 of 189
 
c++ program for Railway reservation
c++ program for Railway reservationc++ program for Railway reservation
c++ program for Railway reservation
 
Writing Domain-Specific Languages for BeepBeep
Writing Domain-Specific Languages for BeepBeepWriting Domain-Specific Languages for BeepBeep
Writing Domain-Specific Languages for BeepBeep
 

Similar to aming distribution: formal protocols for Akka Typed

i need to write a return type function that takes information about th.docx
i need to write a return type function that takes information about th.docxi need to write a return type function that takes information about th.docx
i need to write a return type function that takes information about th.docx
hendriciraida
 
i need to modify this c++ so when the user enter services thats not an.docx
i need to modify this c++ so when the user enter services thats not an.docxi need to modify this c++ so when the user enter services thats not an.docx
i need to modify this c++ so when the user enter services thats not an.docx
hendriciraida
 
Akka Typed — between Session Types and the Actor Model
Akka Typed — between Session Types and the Actor ModelAkka Typed — between Session Types and the Actor Model
Akka Typed — between Session Types and the Actor Model
Roland Kuhn
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
danwrong
 
Introducing the WSO2 Complex Event Processor
Introducing the WSO2 Complex Event ProcessorIntroducing the WSO2 Complex Event Processor
Introducing the WSO2 Complex Event Processor
WSO2
 
Rajeev oops 2nd march
Rajeev oops 2nd marchRajeev oops 2nd march
Rajeev oops 2nd march
Rajeev Sharan
 
i want to add to this c++ code a condition so that you can only chose.docx
i want to add to this c++ code a condition so that you can only chose.docxi want to add to this c++ code a condition so that you can only chose.docx
i want to add to this c++ code a condition so that you can only chose.docx
hendriciraida
 
Coordinating non blocking io melb-clj
Coordinating non blocking io melb-cljCoordinating non blocking io melb-clj
Coordinating non blocking io melb-clj
Logan Campbell
 
Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...
Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...
Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...
Publicis Sapient Engineering
 

Similar to aming distribution: formal protocols for Akka Typed (20)

i need to write a return type function that takes information about th.docx
i need to write a return type function that takes information about th.docxi need to write a return type function that takes information about th.docx
i need to write a return type function that takes information about th.docx
 
i need to modify this c++ so when the user enter services thats not an.docx
i need to modify this c++ so when the user enter services thats not an.docxi need to modify this c++ so when the user enter services thats not an.docx
i need to modify this c++ so when the user enter services thats not an.docx
 
Akka Typed — between Session Types and the Actor Model
Akka Typed — between Session Types and the Actor ModelAkka Typed — between Session Types and the Actor Model
Akka Typed — between Session Types and the Actor Model
 
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
 
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
Powering Heap With PostgreSQL And CitusDB (PGConf Silicon Valley 2015)
 
Creating an Uber Clone - Part XXXII.pdf
Creating an Uber Clone - Part XXXII.pdfCreating an Uber Clone - Part XXXII.pdf
Creating an Uber Clone - Part XXXII.pdf
 
Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)Building @Anywhere (for TXJS)
Building @Anywhere (for TXJS)
 
Introducing the WSO2 Complex Event Processor
Introducing the WSO2 Complex Event ProcessorIntroducing the WSO2 Complex Event Processor
Introducing the WSO2 Complex Event Processor
 
Serverless stateful
Serverless statefulServerless stateful
Serverless stateful
 
CAVE Overview
CAVE OverviewCAVE Overview
CAVE Overview
 
Improving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinImproving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con Berlin
 
Rajeev oops 2nd march
Rajeev oops 2nd marchRajeev oops 2nd march
Rajeev oops 2nd march
 
i want to add to this c++ code a condition so that you can only chose.docx
i want to add to this c++ code a condition so that you can only chose.docxi want to add to this c++ code a condition so that you can only chose.docx
i want to add to this c++ code a condition so that you can only chose.docx
 
ZIO actors by Mateusz Sokół Scalac
ZIO actors by Mateusz Sokół ScalacZIO actors by Mateusz Sokół Scalac
ZIO actors by Mateusz Sokół Scalac
 
Serverless Stateful Architecture
Serverless Stateful ArchitectureServerless Stateful Architecture
Serverless Stateful Architecture
 
Coordinating non blocking io melb-clj
Coordinating non blocking io melb-cljCoordinating non blocking io melb-clj
Coordinating non blocking io melb-clj
 
Small pieces loosely joined
Small pieces loosely joinedSmall pieces loosely joined
Small pieces loosely joined
 
Functional Principles for OO Developers
Functional Principles for OO DevelopersFunctional Principles for OO Developers
Functional Principles for OO Developers
 
Creating a Facebook Clone - Part XXVI - Transcript.pdf
Creating a Facebook Clone - Part XXVI - Transcript.pdfCreating a Facebook Clone - Part XXVI - Transcript.pdf
Creating a Facebook Clone - Part XXVI - Transcript.pdf
 
Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...
Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...
Open XKE - POC d'une architecture distribuée de calculs financiers par Xavier...
 

More from J On The Beach

Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...
Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...
Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...
J On The Beach
 
Axon Server went RAFTing
Axon Server went RAFTingAxon Server went RAFTing
Axon Server went RAFTing
J On The Beach
 
Madaari : Ordering For The Monkeys
Madaari : Ordering For The MonkeysMadaari : Ordering For The Monkeys
Madaari : Ordering For The Monkeys
J On The Beach
 
Machine Learning: The Bare Math Behind Libraries
Machine Learning: The Bare Math Behind LibrariesMachine Learning: The Bare Math Behind Libraries
Machine Learning: The Bare Math Behind Libraries
J On The Beach
 

More from J On The Beach (20)

Massively scalable ETL in real world applications: the hard way
Massively scalable ETL in real world applications: the hard wayMassively scalable ETL in real world applications: the hard way
Massively scalable ETL in real world applications: the hard way
 
Big Data On Data You Don’t Have
Big Data On Data You Don’t HaveBig Data On Data You Don’t Have
Big Data On Data You Don’t Have
 
Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...
Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...
Acoustic Time Series in Industry 4.0: Improved Reliability and Cyber-Security...
 
Pushing it to the edge in IoT
Pushing it to the edge in IoTPushing it to the edge in IoT
Pushing it to the edge in IoT
 
Drinking from the firehose, with virtual streams and virtual actors
Drinking from the firehose, with virtual streams and virtual actorsDrinking from the firehose, with virtual streams and virtual actors
Drinking from the firehose, with virtual streams and virtual actors
 
How do we deploy? From Punched cards to Immutable server pattern
How do we deploy? From Punched cards to Immutable server patternHow do we deploy? From Punched cards to Immutable server pattern
How do we deploy? From Punched cards to Immutable server pattern
 
Java, Turbocharged
Java, TurbochargedJava, Turbocharged
Java, Turbocharged
 
When Cloud Native meets the Financial Sector
When Cloud Native meets the Financial SectorWhen Cloud Native meets the Financial Sector
When Cloud Native meets the Financial Sector
 
The big data Universe. Literally.
The big data Universe. Literally.The big data Universe. Literally.
The big data Universe. Literally.
 
Streaming to a New Jakarta EE
Streaming to a New Jakarta EEStreaming to a New Jakarta EE
Streaming to a New Jakarta EE
 
The TIPPSS Imperative for IoT - Ensuring Trust, Identity, Privacy, Protection...
The TIPPSS Imperative for IoT - Ensuring Trust, Identity, Privacy, Protection...The TIPPSS Imperative for IoT - Ensuring Trust, Identity, Privacy, Protection...
The TIPPSS Imperative for IoT - Ensuring Trust, Identity, Privacy, Protection...
 
Pushing AI to the Client with WebAssembly and Blazor
Pushing AI to the Client with WebAssembly and BlazorPushing AI to the Client with WebAssembly and Blazor
Pushing AI to the Client with WebAssembly and Blazor
 
Axon Server went RAFTing
Axon Server went RAFTingAxon Server went RAFTing
Axon Server went RAFTing
 
The Six Pitfalls of building a Microservices Architecture (and how to avoid t...
The Six Pitfalls of building a Microservices Architecture (and how to avoid t...The Six Pitfalls of building a Microservices Architecture (and how to avoid t...
The Six Pitfalls of building a Microservices Architecture (and how to avoid t...
 
Madaari : Ordering For The Monkeys
Madaari : Ordering For The MonkeysMadaari : Ordering For The Monkeys
Madaari : Ordering For The Monkeys
 
Servers are doomed to fail
Servers are doomed to failServers are doomed to fail
Servers are doomed to fail
 
Interaction Protocols: It's all about good manners
Interaction Protocols: It's all about good mannersInteraction Protocols: It's all about good manners
Interaction Protocols: It's all about good manners
 
A race of two compilers: GraalVM JIT versus HotSpot JIT C2. Which one offers ...
A race of two compilers: GraalVM JIT versus HotSpot JIT C2. Which one offers ...A race of two compilers: GraalVM JIT versus HotSpot JIT C2. Which one offers ...
A race of two compilers: GraalVM JIT versus HotSpot JIT C2. Which one offers ...
 
Leadership at every level
Leadership at every levelLeadership at every level
Leadership at every level
 
Machine Learning: The Bare Math Behind Libraries
Machine Learning: The Bare Math Behind LibrariesMachine Learning: The Bare Math Behind Libraries
Machine Learning: The Bare Math Behind Libraries
 

Recently uploaded

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Recently uploaded (20)

Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
AI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by AnitarajAI in Action: Real World Use Cases by Anitaraj
AI in Action: Real World Use Cases by Anitaraj
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 

aming distribution: formal protocols for Akka Typed

  • 1. Taming Distribution: Formal Protocols for Akka Typed Dr. Roland Kuhn @rolandkuhn — CTO of Actyx
  • 9. Some causality comes naturally.
  • 10. Akka Typed Receptionist API trait ServiceKey[T] sealed trait Command final case class Register[T](key: ServiceKey[T], address: ActorRef[T], replyTo: ActorRef[Registered[T]]) extends Command final case class Registered[T](key: ServiceKey[T], address: ActorRef[T]) final case class Find[T](key: ServiceKey[T], replyTo: ActorRef[Listing[T]]) extends Command final case class Listing[T](key: ServiceKey[T], addresses: Set[ActorRef[T]])
  • 11. … with Unregister support trait ServiceKey[T] sealed trait Command final case class Register[T](key: ServiceKey[T], address: ActorRef[T], replyTo: ActorRef[Registered[T]]) extends Command final case class Registered[T](key: ServiceKey[T], address: ActorRef[T], handle: ActorRef[Unregister]) final case class Unregister(replyTo: ActorRef[Unregistered]) final case class Unregistered() final case class Find[T](key: ServiceKey[T], replyTo: ActorRef[Listing[T]]) extends Command final case class Listing[T](key: ServiceKey[T], addresses: Set[ActorRef[T]])
  • 12. For everything that is not fixed by causality coordination is needed.
  • 13. Static knowledge avoids coordination.
  • 15. Cluster Receptionist • use FQCN of service keys as known identifier
  • 16. Cluster Receptionist • use FQCN of service keys as known identifier • local resolution establishes static type-safety
  • 17. Cluster Receptionist • use FQCN of service keys as known identifier • local resolution establishes static type-safety • CRDT map from keys to sets of ActorRefs
  • 18. Natural causality is not enough!
  • 20. Messages for a payment system case object AuditService extends ServiceKey[LogActivity] case class LogActivity(who: ActorRef[Nothing], what: String, id: Long, replyTo: ActorRef[ActivityLogged]) case class ActivityLogged(who: ActorRef[Nothing], id: Long)
  • 21. Messages for a payment system case object AuditService extends ServiceKey[LogActivity] case class LogActivity(who: ActorRef[Nothing], what: String, id: Long, replyTo: ActorRef[ActivityLogged]) case class ActivityLogged(who: ActorRef[Nothing], id: Long) sealed trait PaymentService case class Authorize(payer: URI, amount: BigDecimal, id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService case class Capture(id: UUID, amount: BigDecimal, replyTo: ActorRef[PaymentResult]) extends PaymentService case class Void(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService case class Refund(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService
  • 22. Messages for a payment system case object AuditService extends ServiceKey[LogActivity] case class LogActivity(who: ActorRef[Nothing], what: String, id: Long, replyTo: ActorRef[ActivityLogged]) case class ActivityLogged(who: ActorRef[Nothing], id: Long) sealed trait PaymentService case class Authorize(payer: URI, amount: BigDecimal, id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService case class Capture(id: UUID, amount: BigDecimal, replyTo: ActorRef[PaymentResult]) extends PaymentService case class Void(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService case class Refund(id: UUID, replyTo: ActorRef[PaymentResult]) extends PaymentService sealed trait PaymentResult case class PaymentSuccess(id: UUID) extends PaymentResult case class PaymentRejected(id: UUID, reason: String) extends PaymentResult case class IdUnkwown(id: UUID) extends PaymentResult
  • 23. Akka Typed crash course case class Greet(whom: String) class Greeter extends akka.actor.Actor { def receive = { case Greet(whom) => println(s"Hello $whom!") } }
  • 24. Akka Typed crash course case class Greet(whom: String) class Greeter extends akka.actor.Actor { def receive = { case Greet(whom) => println(s"Hello $whom!") } } object Greeter { import akka.typed.scaladsl.Actor val behavior = Actor.immutable[Greet] { (ctx, greet) => println(s"Hello ${greet.whom}!") Actor.same } }
  • 25. First actor: do the audit sealed trait Msg private case object AuditDone extends Msg private case object PaymentDone extends Msg private def doAudit(audit: ActorRef[LogActivity], who: ActorRef[AuditDone.type], msg: String) = Actor.deferred[ActivityLogged] { ctx => val id = Random.nextLong() audit ! LogActivity(who, msg, id, ctx.self) ctx.schedule(3.seconds, ctx.self, ActivityLogged(null, 0L)) Actor.immutable { (ctx, msg) => if (msg.who == null) throw new TimeoutException else if (msg.id != id) throw new IllegalStateException else { who ! AuditDone Actor.stopped } } }
  • 26. Second actor: do the payment private def doPayment(from: URI, amount: BigDecimal, payments: ActorRef[PaymentService], replyTo: ActorRef[PaymentDone.type]) = Actor.deferred[PaymentResult] { ctx => val uuid = UUID.randomUUID() payments ! Authorize(from, amount, uuid, ctx.self) ctx.schedule(3.seconds, ctx.self, IdUnkwown(null)) Actor.immutable { case (ctx, PaymentSuccess(`uuid`)) => payments ! Capture(uuid, amount, ctx.self) Actor.immutable { case (ctx, PaymentSuccess(`uuid`)) => replyTo ! PaymentDone Actor.stopped } // otherwise die with MatchError } }
  • 27. Third actor: orchestration of the process def getMoney[R](from: URI, amount: BigDecimal, payments: ActorRef[PaymentService], audit: ActorRef[LogActivity], replyTo: ActorRef[R], msg: R) = Actor.deferred[Msg] { ctx => ctx.watch(ctx.spawn(doAudit(audit, ctx.self, "starting payment"), "preAudit")) Actor.immutable[Msg] { case (ctx, AuditDone) => ctx.watch(ctx.spawn(doPayment(from, amount, payments, ctx.self), "payment")) Actor.immutable[Msg] { case (ctx, PaymentDone) => ctx.watch(ctx.spawn(doAudit(audit, ctx.self, "payment finished"), "postAudit")) Actor.immutable[Msg] { case (ctx, AuditDone) => replyTo ! msg Actor.stopped } } onSignal terminateUponChildFailure } onSignal terminateUponChildFailure }
  • 28. code can employ knowledge in wrong order or existing knowledge is not used at all
  • 29. What if we prescribe effects and their order?
  • 30. Which steps shall be done? • send audit log, get confirmation for that • send Authorize request, get confirmation • send Capture request, get confirmation • send audit log, get confirmation
  • 31. Akka Typed Session: protocol definition object GetMoneyProtocol extends Protocol { type Session = // Send[LogActivity] :: // preAudit Read[ActivityLogged] :: // Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate Send[Authorize] :: // do payment Read[PaymentResult] :: // Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate Send[Capture] :: // Read[PaymentResult] :: // Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate Send[LogActivity] :: // postAudit Read[ActivityLogged] :: // Choice[(Halt :: _0) :+: _0 :+: CNil] :: // possibly terminate _0 }
  • 32. First process: do the audit private def doAudit(audit: ActorRef[LogActivity], who: ActorRef[Nothing], msg: String) = OpDSL[ActivityLogged] { implicit opDSL => val id = Random.nextLong() for { self <- opProcessSelf _ <- opSend(audit, LogActivity(who, msg, id, self)) ActivityLogged(`who`, `id`) <- opRead } yield Done }.withTimeout(3.seconds) /* * the return type is * Process[ActivityLogged, Done, * Send[LogActivity] :: Read[ActivityLogged] :: * Choice[(Halt :: _0) :+: _0 :+: CNil] :: _0] */
  • 33. Second process: do the payment private def doPayment(from: URI, amount: BigDecimal, payments: ActorRef[PaymentService]) = OpDSL[PaymentResult] { implicit opDSL => val uuid = UUID.randomUUID() for { self <- opProcessSelf _ <- opSend(payments, Authorize(from, amount, uuid, self)) PaymentSuccess(`uuid`) <- opRead _ <- opSend(payments, Capture(uuid, amount, self)) PaymentSuccess(`uuid`) <- opRead } yield Done }.withTimeout(3.seconds) /* * the return type is * Process[PaymentResult, Done, * Send[Authorize] :: Read[PaymentResult] :: * Choice[(Halt :: _0) :+: _0 :+: CNil] :: * Send[Capture] :: Read[PaymentResult] :: * Choice[(Halt :: _0) :+: _0 :+: CNil] :: _0] */
  • 34. Third process: orchestrate and verify // this useful process is provided by the Session DSL and talks to the Receptionist def getService[T](key: ServiceKey[T]): Operation[Listing[T], ActorRef[T], _0] def getMoney[R](from: URI, amount: BigDecimal, payments: ActorRef[PaymentService], replyTo: ActorRef[R], msg: R) = OpDSL[Nothing] { implicit opDSL => for { self <- opProcessSelf audit <- opCall(getService(AuditService) .named("getAuditService")) _ <- opCall(doAudit(audit, self, "starting payment").named("preAudit")) _ <- opCall(doPayment(from, amount, payments) .named("payment")) _ <- opCall(doAudit(audit, self, "payment finished").named("postAudit")) } yield replyTo ! msg }
  • 35. Third process: orchestrate and verify // this useful process is provided by the Session DSL and talks to the Receptionist def getService[T](key: ServiceKey[T]): Operation[Listing[T], ActorRef[T], _0] def getMoney[R](from: URI, amount: BigDecimal, payments: ActorRef[PaymentService], replyTo: ActorRef[R], msg: R) = OpDSL[Nothing] { implicit opDSL => for { self <- opProcessSelf audit <- opCall(getService(AuditService) .named("getAuditService")) _ <- opCall(doAudit(audit, self, "starting payment").named("preAudit")) _ <- opCall(doPayment(from, amount, payments) .named("payment")) _ <- opCall(doAudit(audit, self, "payment finished").named("postAudit")) } yield replyTo ! msg } // compile-time verification (TODO: should be a macro) private def verify = E.vetExternalProtocol(GetMoneyProtocol, getMoney(???, ???, ???, ???, ???))
  • 36. Conclusion: There is a lot on the table, get involved! https://github.com/rkuhn/akka-typed-session