Akka Typed — between Session Types and the Actor Model

4,959 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

×