Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Akka Typed — between Session Types and the Actor Model

5,684 views

Published on

Akka Typed — between Session Types and the Actor Model

  1. 1. Akka Typed: Between Session Types and the Actor Model Dr. Roland Kuhn @rolandkuhn — Akka Tech Lead
  2. 2. Actor Model
  3. 3. The Actor Model • Hewitt, Bishop, Steiger,
 “A Universal Modular ACTOR Formalism for Artificial Intelligence”, IJCAI’73, pp 235–245 • a model of distributed independent agents • in response to an incoming message an Actor can • create a finite number of Actors • send a finite number of messages to Actors it knows • designate the behavior to be applied to the next message 3
  4. 4. Concrete Implementation: Akka 4 case class Greet(whom: String) class Greeter extends Actor { def receive = { case Greet(whom) => sender() ! s"Hello $whom!" val delegate = context.actorOf(grumpyProps) context.become(grumpy(delegate)) } def grumpy(delegate: ActorRef): Receive = { case g: Greet => delegate forward g } } val grumpyProps = Props(new Actor { def receive = { case Greet(whom) => sender() ! s"Go away, $whom!" } })
  5. 5. Motivation
  6. 6. Initial Motivation • make Actors re-factoring friendly • avoid stupid mistakes
 (i.e. provide some weak safety properties) 6
  7. 7. Introducing Akka Typed
  8. 8. The Flaws of Previous Implementations • retaining sender() is just not feasible • this feature is inherently dynamic and therefore must go • defining union types for multiple input types proved too complex • TypedChannels used a type map based on HList • verbose syntax and cryptic error messages • use only single type parameter and subsume other types via dedicated adapters (child Actors) 8
  9. 9. The Current Implementation • parameterized ActorRef accepts type T • parameterized Behavior responds to type T • actor creation turns Behavior[T] via Props[T] into ActorRef[-T] • implemented as a thin layer on top of untyped actors • separated the logic from its execution, no more Actor trait 9
  10. 10. Behavior is King, no more Actor trait 10 object Server { sealed trait Command case class Get(id: Int)(val replyTo: ActorRef[Got]) extends Command case class Put(name: String, ref: ActorRef[OtherCommand]) extends Command case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]]) val initial: Behavior[Command] = withMap(Map.empty) private def withMap(map: Map[String, ActorRef[OtherCommand]]) = Total[Command] { case g @ Get(id) => g.replyTo ! Got(id, Map.empty) Same case Put(name, ref) => withMap(map.updated(name, ref)) } }
  11. 11. What can we do with it?
  12. 12. Encoding Types with Members 12 class MyClass { def myMethod(id: Int): String def otherMethod(name: String): Unit protected def helper(arg: Double): Unit }
  13. 13. Encoding Types with Members • Typed Actors provide complete modules with members • Typed Actors can encode more flexible access privileges • more verbose due to syntax being optimized for classes 13 object MyClass { sealed trait AllCommand sealed trait Command extends AllCommand case class MyMethod(id: Int)(replyTo: ActorRef[String]) extends Command case class OtherMethod(name: String) extends Command case class Helper(arg: Double) extends AllCommand val behavior: Behavior[Command] = behavior(42).narrow private def behavior(x: Int): Behavior[AllCommand] = ??? }
  14. 14. Calling Methods 14 object MyClassDemo { import MyClass._ val myClass: MyClass = ??? val myActor: ActorRef[Command] = ??? implicit val t: Timeout = ??? myClass.otherMethod("John") myActor!OtherMethod("John") val result = myClass.myMethod(42) val future = myActor?MyMethod(42) }
  15. 15. But Actors can do more: Protocols 15 object Protocol { case class GetSession(replyTo: ActorRef[GetSessionResult]) sealed trait GetSessionResult case class ActiveSession(service: ActorRef[SessionCommand]) extends GetSessionResult with AuthenticateResult case class NewSession(auth: ActorRef[Authenticate]) extends GetSessionResult case class Authenticate(username: String, password: String, replyTo: ActorRef[AuthenticateResult]) sealed trait AuthenticateResult case object FailedSession extends AuthenticateResult trait SessionCommand }
  16. 16. But Actors can do more: Protocols 16
  17. 17. Session Types
  18. 18. Attempt at a Definition • Session: aunitofconversation • Session Type: thestructureofaconversation,
 a sequence of interactions in a communication- centric program model • originally only binary sessions, multiparty sessions introduced 2008 • primitives are
 sending,receiving,sequence,choice,recursion 18
  19. 19. Scribble • commonly used language for defining protocols • defines the global protocol for all participants • local projection for a single participant preserves safety • automatic generation of FSA for local runtime validation • type discipline for local processes requires support for linear types from the host language • where that is unavailable use dynamic validation 19
  20. 20. Question • Can safety be retained while allowing sessions with dynamically added and removed participants? 20
  21. 21. Question • Does distributed computing fundamentally need nominal types to agree on semantics? 21
  22. 22. Case Study: Type-Safe Receptionist 22 object Receptionist { trait AbstractServiceKey { type Type } trait ServiceKey[T] extends AbstractServiceKey { final override type Type = T } sealed trait Command final case class Register[T](key: ServiceKey[T], address: ActorRef[T]) (val replyTo: ActorRef[Registered[T]]) extends Command final case class Find[T](key: ServiceKey[T])(val replyTo: ActorRef[Listing[T]]) extends Command final case class Registered[T](key: ServiceKey[T], address: ActorRef[T]) final case class Listing[T](key: ServiceKey[T], addresses: Set[ActorRef[T]]) ... }
  23. 23. 23 object Receptionist { ... val behavior: Behavior[Command] = behavior(TypedMultiMap.empty) private type KV[K <: AbstractServiceKey] = ActorRef[K#Type] private def behavior(map: TypedMultiMap[AbstractServiceKey, KV]) = Full[Command] { case Msg(ctx, r: Register[t]) => ctx.watch(r.address) r.replyTo ! Registered(r.key, r.address) behavior(map.inserted(r.key)(r.address)) case Msg(ctx, f: Find[t]) => val set = map get f.key f.replyTo ! Listing(f.key, set) Same case Sig(ctx, Terminated(ref)) => behavior(map valueRemoved ref) } }
  24. 24. Question • the interrupt feature of Scribble introduces non- determinism since messages can be arbitrarily delayed • How much does the theory hinge on guaranteed delivery? • Does the session just cease to exist when nodes fail? 24
  25. 25. Linear Types or Dynamic Actors?
  26. 26. Question • protocol progress between fixed participants implies the destruction of knowledge • Can this notion be replaced by requiring the acquisition or deduction of new knowledge? 26
  27. 27. Question • Instead of relying upon consensus, shouldn’t we maximize the use of causality and causal consistency? 27 Lloyd, Freedman, Kaminsky, Andersen: «Don’t Settle for Eventual: Scalable Causal Consistency for Wide-Area Storage with COPS», SOSP’11, ACM 2011
  28. 28. Dynamic Validation
  29. 29. Dynamic Validation of Actor Behavior • pure internal formulation using an abstract machine (process algebra) • interpreter can run local projection of protocol • rejects sending untimely messages • rejects receiving from inactive channels • due to at-most-once delivery FSA can only advance upon reception of external input (proof of progress) 29
  30. 30. Question • Given the following requirements: • sequencing of actions • dynamic decision how to continue • recursion • composition of actions • injection of plain values • Is there another abstraction than Monad to formulate the API? 30
  31. 31. ©Typesafe 2015 – All Rights Reserved

×