Presentation is loading. Please wait.

Presentation is loading. Please wait.

Advanced Topics in Functional and Reactive Programming: Actor Model & Akka Majeed Kassis.

Similar presentations


Presentation on theme: "Advanced Topics in Functional and Reactive Programming: Actor Model & Akka Majeed Kassis."— Presentation transcript:

1 Advanced Topics in Functional and Reactive Programming: Actor Model & Akka
Majeed Kassis

2 Threads Threads are used to execute code concurrently
Threads contains resources that they are shared Synchronization help guarantee: Correct ordering Visibility Data consistency Problems? Hard to solve deadlocks Hard to maintain data consistency Hard to ensure liveness Locks Shared Memory Waits Thread Thread Dead Lock ! Shared Memory Waits Locks

3 Thread-Based Concurrency Issues
No fault tolerance by default Programmers need to think of all extreme failure cases! Need to handle them one by one. Nondeterminism: Unpredictable thread scheduling The increasing use of Arbiters which controls concurrent access to memory Snapshotting and replication Global state – snapshots – complex to generate! data replication is hard due to shared state!

4 Actor Model – Asynchronous Concurrency
General purpose concurrent programming model Facilitates geographical distribution Strong support for fault tolerance Allows mutable state, but avoids sharing it. Actor: The fundamental unit of concurrent computation in the model. Can be implemented as processes or threads, or any other entity. Benefits: Simple and high-level abstractions for distribution, concurrency and parallelism. Asynchronous, non-blocking and highly performant message-driven programming model. Very lightweight event-driven processes (several million actors per GB of heap memory).

5 An Actor Unit Consists of Three Things
Processing: “Behavior” To get something done Same as objects: Methods Storage: “State” To be able to remember/store things Same as objects: Fields Communication: “Messages” via “MailBoxes” To exchange information between actors Different than objects: Real communication instead of method calling Mailbox Mailbox Behavior State Message Message Message Communication support is added Executors/Threads do not support communication

6 Actor Model – Key Principles
No shared state between actors! Not need for synchronization Each Actor has his own mail-box(es) Used as a buffer for incoming messages Messages are handled sequentially Messages are passed asynchronously The receives does not need to immediately handle the sent message Actors can create new Actors No single ‘manager’ of the system.

7 Messages in Actor Model
Actors exchange information by sending messages. Messages are sent asynchronously Receiving Actors do not block waiting for a message. Messages are stored in an Actor ‘mail-box’ (called ‘channel’ as well) A queue with multiple producers – other actors sending messages And a single consumer – the actor handles these messages sequentially Messages are immutable! They can be handled by the actor Or, they can be propagated as is – without modification

8 Reactions Upon Message Receive
Actor can send a finite number of messages to other actors Actors may have multiple mail-boxes Actors are addressed Can have no address, one address, or multiple addresses Actor can spawn a finite number of new actors Actor change its own internal behavior This occurs when a control message is received Takes effect when the next incoming message is handled! Behavior is stacked and can be popped or pushed as needed

9 Fault Tolerance Uses “let is crash” philosophy Implementation Example
Instead of programming defensively, allow critical code to crash! Once crashed, a monitoring process receives a message and it needs: Message is received from a supervisor Actor To restore the state to a stable one: Stop or restart crashed actor Allows creating “self-healing” systems! Implementation Example Each Actor code is ran in a process, isolated, with their own state Monitoring process acts as a supervisor Receives message on Actor crash Restores to safe state, can be done via rollback partial changes Restart crashed Actor, mostly with initial state Can also stop actor, or delegate problem upward We can just have one exception catch clause, send a message and exit. No need to handle any special case that we didn’t anticipate or thought about.

10 Actor Model Characteristics
Messages are sent asynchronously They can take arbitrarily long to eventually arrive in the mailbox of the receiver. There is no guarantees on the ordering of messages. Queuing and de-queuing of messages in a mailbox are atomic operations There cannot be a race condition. Incoming messages are processed sequentially

11 Actor Model Characteristics
Reacting Actor changes its own internal behavior, allows to deal with mutable state The new behavior is applied after the current message has been handled Every message handling run still represents a side-effect free operation from a conceptual perspective Allows modelling inherently concurrent systems Each actor is entirely independent of any other instances. There is no shared state – no sharing of references or pointers using messages Interaction between actors is purely based on asynchronous messages

12 Message Passing Implementations
Most implementations ensure that two messages sent from one actor to another maintain their order at arrival. Messaging is always asynchronous: tell(): Send request, no need for response [Fire-Forget] ask(): Send request, expect response [Ask forward(): Send request asking it to be forwarded to 3rd party. Messages: Can be any object Should be immutable Should be serializable

13 Message Handling Implementations
Most implementations provide pattern matching. This enables the developer to distinguish between different types of messages and supply different handling code associated to the type of message. While receiving messages is a blocking operation from the actor's perspective, sending new messages is always non-blocking. Some implementations also provide selective receive semantics. Depending on its behavior, an actor may then wait for a specific message in the mailbox and temporarily defer others.

14 Actor Model Programing Languages
Erlang: Programming language based on actor model Introduced in 1986 by Ericsson Elixir: Wrapper of Erlang language Dynamic, functional language designed for building scalable and maintainable applications. By Plataformatic, in 2011

15 Actor Model Libraries Akka: C++ Actor Framework: CAF_C++
Apache’s toolkit and runtime for building highly concurrent, distributed, and resilient message-driven applications on the JVM. By Lightbend in 2009 C++ Actor Framework: CAF_C++ Implemented in C++11 Uses Work-Stealing Scheduling Lockfree implementation of mailboxes using CAS operation for enqueue/dequeue Presented in 2011, open source!

16 Akka Mailboxes Akka toolkit has many types of mailboxes:
Blocking and non-blocking queues Bounded and non-bounded queues Priority queues Control aware queues Akka also allows making custom defined queues. By implementing “MailBoxType” interface You can implement your own priority queue! Control aware = an actor needs to be able to receive control messages immediately no matter how many other messages are already in its mailbox.

17 Akka: Built-In MailBox Types
UnboundedMailbox  SingleConsumerOnlyUnboundedMailbox NonBlockingBoundedMailbox UnboundedControlAwar box UnboundedPriorityMailbox UnboundedStablePriorityMailbox BoundedMailbox BoundedPriorityMailbox BoundedStablePriorityMailbox BoundedControlAwar box

18 Actor: 4 Core Operations
Define: Implement a new Actor Implements the behavior of the actor: how to handle message receive Create: Instantiate a new Actor Send: Send a message to an Actor Three kinds: Fire-Forget, send a message asynchronously and return immediately Ask-Reply, sends a message asynchronously and returns a Future representing a possible reply Forward, forward a message from one actor to another Become: Change the behavior (algorithm) of an Actor dynamically! This takes effect beginning from the next message onward. Supervise: Manage another Actor failure Dynamically: during runtime!

19 Creating an Actor Each Actor is represented by an ActorRef
You never get access to an Actor instance An Actor reference allows sending messages to an Actor Receving is done in asynchronous manner! final ActorRef printerActor = system.actorOf(Printer.props(), "printerActor"); final ActorRef howdyGreeter = system.actorOf(Greeter.props("Howdy", printerActor), "howdyGreeter"); final ActorRef helloGreeter = system.actorOf(Greeter.props("Hello", printerActor), "helloGreeter"); final ActorRef goodDayGreeter = system.actorOf(Greeter.props("Good day", printerActor), "goodDayGreeter");

20 Actor Hierarchies Actors can form hierarchies. Foo is a base actor

21 Actor Hierarchies Actors can form hierarchies.
A is a child actor of Foo

22 Actors Name Resolution

23 Actor Hierarchy: Child Actors
The use of child actors Delegate work to a child actor which increases resiliency and responsiveness A child actor is created to do the handling of a specific event The result is forwarded to the original sender, not the parent actor Managing Exceptions Actors can manage exceptions thrown by child actors SupervisorStrategy is created to map each exception with its handling Can be used to stop or restart child

24 Akka System Default Actor
Hierarchy Actors can form hierarchies Akka System Default Actor akka://application/user ActorRef supervisor = Akka.system().actorOf(Props.create(SupervisorActor.class), “Supervisor”); Supervisor Actor parent akka://application/user/Supervisor ActorRef child = getContext().actorOf(Props.create(ChildActor.class), “Child”); Child Actor child akka://application/user/Supervisor/Child

25 Actor Hierarchy / the so-called root guardian. This is the parent of all actors in the system, and the last one to stop when the system itself is terminated. /user the guardian. This is the parent actor for all user created actors. Don’t let the name user confuse you, it has nothing to do with end users, nor with user handling. Every actor you create using the Akka library will have the constant path /user/ prepended to it. /system the system guardian.

26 Actor Reference An actor reference is a subtype of ActorRef
Its main purpose is to support sending messages to the actor it represents. Each actor has access to its canonical (local) reference through the self field this reference is also included as sender reference by default for all messages sent to other actors. During message processing the actor has access to a reference representing the sender of the current message through the sender() method. Two general categories for obtaining Actor Referneces: creating actors - using ActorSystem.actorOf() looking up actors – using ActorSystem.actorSelection()

27 Actor Path Actors are created in a hierarchical fashion
There exists a unique sequence of actor names given by recursively following the supervision links between child and parent down towards the root of the actor system. This sequence can be seen as enclosing folders in a file system, hence we adopted the name “path” to refer to it, although actor hierarchy has some fundamental difference from file system hierarchy. An actor path consists of: An anchor, which identifies the actor system Followed by the concatenation of the path elements, From root guardian to the designated actor The path elements are the names of the traversed actors and are separated by slashes.

28 Actor Path: Example

29 Actor Path Anchors Each actor path has an address component Examples:
describing the protocol and location by which the corresponding actor is reachable followed by the names of the actors in the hierarchy from the root up Examples: "akka://my-sys/user/service-a/worker1" // purely local // remote

30 Defining Greeter Actor: 1
public class Greeter extends AbstractActor { static public Props props(String message, ActorRef printerActor) { return Props.create(Greeter.class, () -> new Greeter(message, printerActor)); } static public class WhoToGreet { public final String who; public WhoToGreet(String who) { this.who = who; } static public class Greet { public Greet() { }

31 Defining Greeter Actor: 2
private final String message; private final ActorRef printerActor; private String greeting = ""; public Greeter(String message, ActorRef printerActor) { this.message = message; this.printerActor = printerActor; } @Override public Receive createReceive() { return receiveBuilder() .match(WhoToGreet.class, wtg -> { this.greeting = message + ", " + wtg.who; }) .match(Greet.class, x -> { printerActor.tell(new Greeting(greeting), getSelf()); }).build();

32 Defining Printer Actor:
public class Printer extends AbstractActor { static public Props props() { return Props.create(Printer.class, () -> new Printer()); } static public class Greeting { public final String message; public Greeting(String message) { this.message = message; } private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this); public Printer() { } @Override public Receive createReceive() { return receiveBuilder() .match(Greeting.class, greeting -> { log.info(greeting.message); }).build();

33 Creating a new Actor with a non-default MailBox type
public class HelloActor extends Controller { public static Result index() { ActorRef greeter = Akka.system().actorOf(Props.create(GreeterActor.class, “Greeter”) .withMailBox(“akka.dispatch.UnboundedMailbox”)); return ok("ok"); } Can create 2.7 million instances per GB of RAM! package controllers; import akka.actor.ActorRef; import akka.actor.Props; import play.libs.Akka; import play.mvc.*;

34 Sending Messages Sending a message is done by using the destination actor reference Messages in Actor Model are addressed Types of messages: Tell: Fire and Forget [Asynchronous and Non-blocking] Ask: Ask and Reply [Blocking] Forward: Forwarding the received message Messages must be immutable!

35 Sending a message to an Actor
package controllers; public class HelloActor extends Controller { public static Result index() { ActorRef actor = Akka.system().actorOf(Props.create(Greeter.class, “Greeter”)); actor.tell("Hello Actor!!", null); //send a message, no reply expected! return ok("ok"); } Type of sending messages: Tell: Fire and Forget Ask: Ask and Reply Forward: Forward import akka.actor.ActorRef; import akka.actor.Props; import play.libs.Akka; import play.mvc.*; Akka.system() – Creates a new system Props.create() – Creates a new configuration

36 A Tell B Target.tell(message, sender); null ActorRef.noSender()
Object ActorRef To send a message to an actor, you need an Actor reference Asynchronous and Non-blocking (Fire-and-forget) null ActorRef.noSender() getSelf()

37 A Tell B Target.tell(message, sender);
public void onReceive(Object message){ if (message instanceof String) { System.out.println((String) message); System.out.println("getSender()="+ getSender()); }

38 A Tell B Target.tell(message, sender);
ActorRef Object ActorRef EXAMPLE: B.tell(“Hello Actor”,ActorRef.noSender()); B.tell(new Person(“David”,”Chang”),getSelf());

39 A Ask B 1 2 3 getSender().tell(reply_message, getSelf());
Target Ask A message B reply 1 Future<Object> rt = Patterns.ask(Target, message, timeout); 2 getSender().tell(reply_message, getSelf()); 3 String result = Await.result(rt , timeout.duration);

40 Ask public class HelloActor extends Controller {
public static Result index() { ActorRef actor = Akka.system().actorOf(Props.create(AnActor.class)); final Timeout timeout = new Timeout(Duration.create(1, SECONDS)); Future<Object> rt = Patterns.ask(actor,"What's your name?", timeout); try { String result = (String) Await.result(rt, timeout.duration()); System.out.println("The name is "+result); return ok("The name is "+result); } catch (Exception e) { System.out.println(e); } return ok("");

41 Ask import akka.actor.UntypedActor; import akka.japi.Procedure;
public class AnActor extends UntypedActor { public void onReceive(Object message){ if(message.equals("What's your name?")){ getSender().tell("David",getSelf()); }else if (message instanceof String) { System.out.println((String) message); }else{ System.out.println("Unhandled message"); }

42 A Forward B C Target.forward(message, getContext());
ActorContext Target.tell(message, getSender()); ActorRef

43 Back to Example: Executing
public class Driver { public static void main(String[] args) { final ActorSystem system = ActorSystem.create("helloakka"); try { final ActorRef printerActor = system.actorOf(Printer.props(), "printerActor"); final ActorRef howdyGreeter = system.actorOf(Greeter.props("Howdy", printerActor), "howdyGreeter"); final ActorRef helloGreeter = system.actorOf(Greeter.props("Hello", printerActor), "helloGreeter"); final ActorRef goodDayGreeter = system.actorOf(Greeter.props("Good day", printerActor), "goodDayGreeter"); howdyGreeter.tell(new WhoToGreet("Akka"), ActorRef.noSender()); howdyGreeter.tell(new Greet(), ActorRef.noSender()); howdyGreeter.tell(new WhoToGreet("Lightbend"), ActorRef.noSender()); helloGreeter.tell(new WhoToGreet("Java"), ActorRef.noSender()); helloGreeter.tell(new Greet(), ActorRef.noSender()); goodDayGreeter.tell(new WhoToGreet("Play"), ActorRef.noSender()); goodDayGreeter.tell(new Greet(), ActorRef.noSender()); } catch (IOException ioe) { } finally { system.terminate(); } } }

44 Become/Unbecome Akka supports hotswapping the Actor’s behavior at runtime: Invoke the context.become() method from within the Actor. become takes a PartialFunction<Object, BoxedUnit> It implements the new message handler. Become Variants: The hotswapped code is kept in a Stack which can be pushed and popped. Unbecome is used to revert to previous behavior The hotswapped code is replaced completely, by a new behavior. Unbecome is never used. Become explicitly defines a new behavior Note: The actor will revert to its original behavior when restarted by its Supervisor

45 Become: Explicit Behavior Change
static class HotSwapActor extends AbstractActor { private AbstractActor.Receive angry; private AbstractActor.Receive happy; public HotSwapActor() { angry = receiveBuilder() .matchEquals( "foo", s -> { getSender().tell("I am already angry?", getSelf()); }) .matchEquals( "bar", s -> { getContext().become(happy); }) .build(); happy = receiveBuilder() .matchEquals( "bar", s -> { getSender().tell("I am already happy :-)", getSelf()); }) .matchEquals( "foo", s -> { getContext().become(angry); }) } public Receive createReceive() { return receiveBuilder() .matchEquals("foo", s -> getContext().become(angry)) .matchEquals("bar", s -> getContext().become(happy))

46 Top-Level Supervisors: /user - The Guardian Actor
Actors created using system.actorOf() are children of this actor. When this guardian terminates all normal actors in the system will be shutdown as well! Its supervisor strategy determines how the top-level normal actors are supervised When the guardian escalates a failure The root guardian’s response will be to terminate the user guardian Which in effect will shut down the whole actor system.

47 Top-Level Supervisors: /system - The System Guardian
Used to allow an orderly shut-down sequence Where logging remains active while all normal actors terminate It initiates its own shut-down upon reception of the Terminated message. Terminated message is received from /user guardian upon system shutdown. The top-level system actors are supervised using a strategy which will restart indefinitely upon all types of Exception ActorInitializationException and ActorKilledException, will terminate the child in question.

48 Top-Level Supervisors: / - The Root Guardian
The grand-parent of all top-level actors Supervises all the special actors mentioned in Top-Level Scopes for Actor Paths Uses the SupervisorStrategy.stoppingStrategy as a supervision strategy SupervisorStrategy.stoppingStrategy Used to terminate the child upon any type of Exception. Other types of throwables will be escalated to the system System’s isTerminated set to true once root guardian is fully terminated All children recursively stopped

49 Supervise – Fault Tolerance
SUPERVISE (monitor): manage another Actor’s failures Error handling in actors is handle by letting Actors monitor each other for failure This means that if an Actor crashes, a notification will be sent to his supervisor, who can react upon the failure: Stop - The stream is completed with failure Resume - The element is dropped and the stream continues Restart - The element is dropped and the stream continues after restarting the stage. Restarting a stage means that any accumulated state is cleared. This is typically performed by creating a new instance of the stage. Every single actor has a default supervisor strategy. Which is usually sufficient But it can be overridden

50 Setting Up Akka Getting Started: HelloActor Tutorial:
Prerequisites/Download/IDE Integration Using Akka with Maven or SBT HelloActor Tutorial: Complete Akka Guide:

51 Routing Router: An object used to pass a message to multiple Actors.
Messages can be sent via a router to efficiently route them to destination actors, known as its Routees. Routees: A list of Actors the Router sends the message to. Using Routers inside Actors: An actor can have a router as a local variable. Used for this specific Actor following its implemented behavior Router Actor: A self contained actor that manages the Routees itself Only purpose is to It can loads routing logic and other settings from configuration

52 Router Actor: Types of Router Actors
Pool Based – The router creates routees as child actors The router are automatically removed from the router if they terminate Group Based – The routee actors are created externally to the router. The router sends messages to the specified path using actor selection This type does not watching for terminating actors. ActorRef myRouter = getContext().actorOf(new RoundRobinPool(5).props(Props.create(Worker.class)), “myRouter"); List<String> paths = Arrays.asList("/user/workers/w1", "/user/workers/w2", "/user/workers/w3"); ActorRef router4 = getContext().actorOf(new RoundRobinGroup(paths).props(), "router4");

53 Router Logic RoundRobinRoutingLogic RandomRoutingLogic
SmallestMailboxRoutingLogic BroadcastRoutingLogic ScatterGatherFirstCompletedRoutingLogic TailChoppingRoutingLogic ConsistentHashingRoutingLogic

54 Broadcast Messages Used to send a message to all of a router's routees. When a router receives a Broadcast message, It will broadcast that message's payload to all routees No matter how that router would normally route its messages! Code: router.tell(new Broadcast( "Watch out for Davy Jones' locker"), getTestActor());

55 Become/Unbecome Allows changing the behavior of the Actor after instantiation. “Hot Swapping” – changing during runtime Can be done in two ways: Explicit Call It will replace the current behavior (i.e. the top of the behavior stack) No use of unbecome! The needed behavior is explicitly installed. Behavior Stack This behavior is not the default one used in Akka! Must ensure that the number of “pop” operations (i.e. unbecome) matches the number of “push” ones in the long run. otherwise this amounts to a memory leak.

56 Initializing an Actor Initialization via constructor
Done by implementing a constructor Initialization via prestart Done by overriding prestart() method Initialization via message passing Done by overriding createReceive() method

57 Initialization via constructor
Done by implementing the actor constructor And creating a new instance using “new” prior adding it to the system Benefit: Allows using val fields to store any state that does not change during the life of the actor instance Drawback: The constructor is invoked for every incarnation of the actor This means child Actors will also be initialized to their original state.

58 Initialization via prestart
Done by overwriting preStart() function. Instantiation: preStart() of an actor is only called once directly during the initialization of the first instance, that is, at creation of its ActorRef. In the case of restarts, preStart() is called from postRestart(), therefore if not overridden, preStart() is called on every incarnation. However, overriding postRestart() one can disable this behavior, and ensure that there is only one call to preStart(). One useful usage of this pattern is to disable creation of new ActorRefs for children during restarts. This can be achieved by overriding preRestart() Which means child Actors are not reset due to parent Actor restart.

59 Default preStart() Implementation
@Override public void preStart() { // Initialize children here } // Overriding postRestart to disable the call to preStart() after restarts @Override public void postRestart(Throwable reason) {} // The default implementation of preRestart() stops all the children // of the actor. To opt-out from stopping the children, we // have to override preRestart() public void preRestart(Throwable reason, Optional<Object> message) throws Exception { // Keep the call to postStop(), but no stopping of children postStop();

60 Initialization via message passing
Done by overwriting createReceive() function Behavior of the Actor is implemented using become() function. Benefits: Allows dynamic creation of new Actors during runtime Sometimes parameters cannot all be passed to constructor Due to it being unavailable at that time Notes: This pattern should be applied only when none of the other patterns are applicable. Potential issue: Initializer messages might be lost when sent to remote actors. Publishing an ActorRef in an uninitialized state might lead to the condition that it receives a user message before the initialization has been finished

61 Initialization Message: Code Example
@Override public Receive createReceive() { return receiveBuilder() .matchEquals( "init", m1 -> { initializeMe = "Up and running"; getContext() .become( receiveBuilder() “Are you OK?", m2 -> { getSender().tell(initializeMe, getSelf()); }) .build()); }) .build(); }

62 Stopping Actors First, the actor suspends its mailbox processing and sends a stop command to all its children. Then, it keeps processing the internal termination notifications from its children until the last one is gone Finally terminating itself: Invoking postStop() – used to clean resources on shutdown. Dumping mailbox Publishing Terminated on the DeathWatch Telling its supervisor This ensures that actor system sub-trees terminate in an orderly fashion: Propagating the stop command to the leaves Collecting their confirmation Sending it back to the stopped supervisor If one of the actors does not respond, this whole process will be stuck! Once an Actor is stopped: New messages are sent to “deadLetters” mailbox of the ActorSystem. No response from actor is due to processing a message for extended periods of time and therefore not receiving the stop command.

63 Stopping Actor: Methods
Code: actorSystemRef.stop(anActorRef) Shuts down an Actor immediately. PoisonPill: akka.actor.PoisonPill message can be sent to stop an Actor. The actor will stop once the message is processed. PoisonPill is enqueued as ordinary messages! It is handled after the messages already queued in the mailbox. Code: victim.tell(akka.actor.PoisonPill.getInstance(), ActorRef.noSender()); Graceful Stop: Allows termination or compose ordered termination of several actors. Uses Futures in order to receive a notification once the Actor has stopped.

64 Graceful Stop: Code Example
public static final Shutdown SHUTDOWN = Shutdown.Shutdown; try { CompletionStage<Boolean> stopped = gracefulStop(actorRef, Duration.create( 5, TimeUnit.SECONDS), SHUTDOWN); stopped.toCompletableFuture().get(6, TimeUnit.SECONDS); // the actor has been stopped } catch (AskTimeoutException e) { // the actor wasn't stopped within 5 seconds } CompletionStage<Boolean> is the Future object.

65 Router’s Specially Handled Messages
Broadcast Messages Message sent to router and routed automatically to all routees PoisonPill Used to stop the router Can also be used to stop all routees once owrapped by a broadcast message Kill Messages Used to kill the router so it can be stopped/resumed/restarted Management Messages Used to add/remove routes and receive information from router

66 PoisonPill Messages If a router receives this message, the router itself will be stopped. It will not be sent on to routees! To send a PoisonPill message to Router routees: Wrap a PoisonPill message inside a Broadcast message Each routee will receive the PoisonPill message. Note: this will stop all routees, even if the routees aren't children of the router. Code: router.tell(new Broadcast(PoisonPill.getInstance()), getTestActor()); If all routees of a router are stopped, the router itself will stop automatically. Only dynamic router, e.g. using a resizer stays on after all its routees have stopped.

67 Kill Messages Kill message received is handled internally by the router Can be wrapped by Broadcast message to be routed to routees. The router will throw an ActorKilledException and fail. It will then be either resumed, restarted or terminated, depending on supervision strategy. Routees that are children of the router will also be suspended, They will be affected by the supervision directive that is applied to the router. Routees that are not the routers children will not be affected. i.e. those that were created externally to the router, will not be affected. Kill Router: router.tell(Kill.getInstance(), getTestActor()); Kill Routees: router.tell(new Broadcast(Kill.getInstance()), getTestActor());

68 Fault Tolerance In Akka : Types of Supervision Strategies:
Each actor is the supervisor of its children Each actor defines fault handling supervisor strategy Defined strategy cannot be changed after defining it Types of Supervision Strategies: Resume the Actor, keeping its accumulated internal state Restart the Actor, clearing out its accumulated internal state Stop the Actor permanently Escalate the failure, thereby failing itself

69 Actor Restart – Sequence of Events
Suspend the actor, and recursively suspend all children Which means that it will not process normal messages until resumed Call the old instance’s preRestart() hook defaults to sending termination requests to all children and calling postStop() Wait for all children which were requested to terminate (using context.stop()) during preRestart to actually terminate This is a non-blocking operation The termination notice from the last killed child will effect the progression to the next step Create new actor instance by invoking the originally provided factory again Invoke postRestart() on the new instance which by default also calls preStart() Send restart request to all children which were not killed in step 3; restarted children will follow the same process recursively, from step 2 Resume the actor

70 Management Messages These messages are sent to routers.
akka.routing.GetRoutees: Will make it send back its currently used routees in an akka.routing.Routees message. akka.routing.AddRoutee Will add that routee to its collection of routees. akka.routing.RemoveRoutee Will remove that routee to its collection of routees. akka.routing.AdjustPoolSize to a pool router actor Will add or remove that number of routees to its collection of routees. These management messages may be handled after other messages, so if you send AddRoutee immediately followed by an ordinary message you are not guaranteed that the routees have been changed when the ordinary message is routed. If you need to know when the change has been applied you can send AddRoutee followed by GetRoutees and when you receive the Routees reply you know that the preceding change has been applied.

71 Getting Started: Remote Actor HelloWorld
Ability to send message from client to server – remotely! Client may send two types of messages to server: Message.GREET Message.DONE Changes: Modify “application.conf” to support remote communication Modify Client actor to “select” Server Actor for message passing.

72 Modifying Server “application.conf”
akka { loglevel = INFO actor { provider = remote } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = " " port = } } }

73 Server Main import akka.actor.ActorSystem; import akka.actor.Props; public class Main2 { public static void main(String[] args) { //creating the system ActorSystem system = ActorSystem.create("HelloWorldSystem"); //creating system actors system.actorOf(Props.create(Greeter.class), "Greeter"); } }

74 Server “Greeter” Actor
enum Message implements Serializable { GREET, DONE; } public class Greeter extends AbstractActor { @Override public Receive createReceive() { return receiveBuilder() matchEquals(Message.GREET, m -> { System.out.println("Hello World!"); sender().tell(Message.DONE, self()); }) matchEquals(Message.DONE, m -> { System.out.println("Client Disconnected!"); }) build(); } } Serializable is not recommended. User Akka serialization instead

75 Modifying Client “application.conf”
akka { loglevel = INFO actor { provider = remote } remote { enabled-transports = ["akka.remote.netty.tcp"] netty.tcp { hostname = " " port = } } }

76 Client Main public class Main { public static void main(String[] args) { akka.Main.main(new String[] { HelloWorld.class.getName() }); } } Simple client main file with 1 Actor only. You may use the server main implementation instead if this implementation is too simple. This defines HelloWorld class as the system Actor.

77 Client Remote HelloWorld
enum Message implements Serializable { GREET, DONE; } public class HelloWorld extends AbstractActor public Receive createReceive() { return receiveBuilder() .matchEquals(Message.DONE, m -> { // when the greeter is done, stop this actor and with it the application sender().tell(Message.DONE, self()); getContext().stop(self()); }) .build(); public void preStart() { // this is the first step once the Actor is added to the system. ActorSelection greeter = getContext().actorSelection( greeter.tell(Message.GREET, self()); } } matchEquals() is used to check if the message itself equals the value. i.e. .matchEquals(Msg.DONE, …) match() is used to check whether the message object type equals some class. i.e. .match(Msg.class, …)

78 Required Dependencies: Actor and Remote
These dependencies are added to the pom.xml file. They are automatically downloaded using Maven on first execution. <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-actor_2.12</artifactId> <version>2.5.22</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-remote_2.12</artifactId> <version>2.5.22</version> </dependency> These are added to the pom.xml file, Maven will automatically download the needed Akka Jars

79 Getting Started: Passworded Alarm Clock Example
static class Alarm extends AbstractLoggingActor { // protocol static class Activity {} static class Disable { private final String password; public Disable(String password) { this.password = password; } static class Enable { public Enable(String password) {

80 Implementing Alarm Behaviors
private final String password; private final PartialFunction<Object, BoxedUnit> enabled; private final PartialFunction<Object, BoxedUnit> disabled; public Alarm(String password) { this.password = password; enabled = ReceiveBuilder .match(Activity.class, this::onActivity) .match(Disable.class, this::onDisable) .build(); disabled = ReceiveBuilder .match(Enable.class, this::onEnable) // set default behavior receive(disabled); } We have three message types to be received, then for each message type we implement a handling function

81 Implementing Message Handlers: 1
private void onActivity(Activity ignored) { log().warning("oeoeoeoeoe, alarm alarm!!!"); } private void onEnable(Enable enable) { if (password.equals(enable.password)) { log().info("Alarm enable"); getContext().become(enabled); } else { log().info("Someone failed to enable the alarm"); }

82 Implementing Message Handlers: 2
private void onDisable(Disable disable) { if (password.equals(disable.password)) { log().info("Alarm disabled"); getContext().become(disabled); } else { log().warning(“Wrong password received!"); }

83 Passing Actor Fields to Akka “Props”
public static Props props(String password) { return Props.create(Alarm.class, password); } akka.actor.Props configuration object must know about the password attribute Without notifying it by the Actor field It will not pass it to the actual constructor when the actor system is started. We override the default props() function of AbstractActor This function is considered our “constructor” Since we do not access the constructor explicitly.

84 Creating and Executing the Actor System
ActorSystem system = ActorSystem.create(); final ActorRef alarm = system.actorOf(Alarm.props("cat"), "alarm") alarm.tell(new Alarm.Activity(), ActorRef.noSender()); alarm.tell(new Alarm.Enable("dogs"), ActorRef.noSender()); alarm.tell(new Alarm.Enable("cat"), ActorRef.noSender()); alarm.tell(new Alarm.Disable("dogs"), ActorRef.noSender()); alarm.tell(new Alarm.Disable("cat"), ActorRef.noSender());

85


Download ppt "Advanced Topics in Functional and Reactive Programming: Actor Model & Akka Majeed Kassis."

Similar presentations


Ads by Google