akka typed — between session types and the actor model

31
Akka Typed: Between Session Types and the Actor Model Dr. Roland Kuhn @rolandkuhn — Akka Tech Lead

Upload: roland-kuhn

Post on 06-Aug-2015

2.942 views

Category:

Documents


1 download

TRANSCRIPT

Akka Typed: Between Session Types

and the Actor ModelDr. Roland Kuhn

@rolandkuhn — Akka Tech Lead

Actor Model

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

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!" }})

Motivation

Initial Motivation

• make Actors re-factoring friendly

• avoid stupid mistakes(i.e. provide some weak safety properties)

6

Introducing Akka Typed

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

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

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)) }}

What can we do with it?

Encoding Types with Members

12

class MyClass {

def myMethod(id: Int): String def otherMethod(name: String): Unit protected def helper(arg: Double): Unit

}

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] = ???}

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)}

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}

But Actors can do more: Protocols

16

Session Types

Attempt at a Definition

• Session: a unit of conversation

• Session Type: the structure of a conversation,a sequence of interactions in a communication-centric program model

• originally only binary sessions, multiparty sessions introduced 2008

• primitives aresending, receiving, sequence, choice, recursion

18

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

Question

• Can safety be retained while allowing sessions with dynamically added and removed participants?

20

Question

• Does distributed computing fundamentally need nominal types to agree on semantics?

21

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

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) }}

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

Linear Types or

Dynamic Actors?

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

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

Dynamic Validation

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

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

©Typesafe 2015 – All Rights Reserved