scala.actor
is deprecated. Caution: Many articles on the web
are based on scala.actor. Use import akka.actor
.
http://docs.scala-lang.org/overviews/core/actors-migration-guide.html
case class Greeting (who: String) class GreetingActor extends Actor { def receive = { case Greeting(who) => sender ! (s"Hello, $who! Thanks.") } }
val acsy = ActorSystem("WSU-CEG-7370-Actors") val grtr = acsy . actorOf(Props[GreetingActor], "greeter") grtr ! Greeting("Brad Pitt")
Props
is a configuration class to specify options for the creation of actors.
import akka.actor.{ ActorRef, ActorSystem, Props, Actor }
public class Greeting implements Serializable { public final String who; public Greeting(String who) { this.who = who; } }
public class GreetingActor extends UntypedActor { LoggingAdapter log = Logging.getLogger(getContext().system(), this); public void onReceive(Object message) throws Exception { if (message instanceof Greeting) getSender.tell("Hello " + ((Greeting) message).who + " Thanks."); } }
ActorSystem acsy = ActorSystem.create("WSU-CEG-7370-Actors"); ActorRef grtr = acsy . actorOf( new Props(GreetingActor.class), "greeter"); grtr.tell(new Greeting("Brad Pitt"));
case _ => ...
victim ! Kill
context.system.shutdown()
the ActorSystem when
everything’s finished
ActorSystem acsy = ActorSystem.create("WSU-CEG-7370-Actors");
receive
defines how messages are handled.
!
aka tell
.
def ! (message: Any)
(implicit sender: ActorRef = Actor.noSender)
?
sends a message asynchronously and returns a Future
representing a possible reply. Aka ask
.
import akka.actor._ class HotSwapActor extends Actor { import context._ def angry: Receive = { case "ang" => sender ! "I am already angry >:(" case "hap" => become(happy) } def happy: Receive = { case "hap" => sender ! "I am already happy :-)" case "ang" => become(angry) } def receive = { case "ang" => become(angry) case "hap" => become(happy) } }
context.become
Replaces the current behavior (i.e., the top of the
behavior stack)
context.unbecome
pop the stack
import akka.actor.FSM
become
, Finite State Machines, and P3import akka.event.Logging; import akka.actor._ case object Swap class Swapper extends Actor { import context._ val log = Logging(system, this) def receive = { case Swap => log.info("Hi") become({ case Swap => log.info("Ho") unbecome() // just for fun }, discardOld = false) /* not replace */ }} object SwapperApp extends App { val sys = ActorSystem("SwapperSystem") val a = sys.actorOf(Props[Swapper], name="swapper") // alternately logs Hi, Ho, ... a!Swap; a!Swap; a!Swap; a!Swap; a!Swap; a!Swap }
restart
, stop
it, or
escalate
the failure up the hierarchy of actors.
Terminated
message provided by the
DeathWatch
component of the actor system.
import akka.actor.{ Actor, Props, Terminated } class WatchActor extends Actor { val child = context.actorOf(Props.empty, "child") context.watch(child) // registration var lastSender = system.deadLetters def receive = { case "kill" => context.stop(child); lastSender = sender() case Terminated(`child`) => lastSender ! "finished" } }
Terminated(`child`)
akka.routing
strategies:
ExecutionContext
is similar to java.util.concurrent.
Executor
.
import scala.concurrent.ExecutionContext
ExecutionContext
interface.
MessageDispatcher
, and that
dispatcher doubles as an ExecutionContext
.
class PrintActor extends Actor { def receive = { case x ⇒ println(x) } } val printer = system.actorOf(Props[PrintActor])
TimerBasedThrottler
val throttler = system.actorOf( Props(classOf[ TimerBasedThrottler ], 3 msgsPer 1.second)) throttler ! SetTarget(Some(printer)) throttler ! "1"; throttler!"2"; throttler!"3" // These will wait for a second throttler ! "4"; throttler ! "5"
akka.pattern.CircuitBreaker
, …
class D extends Actor with ActorLogging { import context.dispatcher val breaker = new CircuitBreaker( context.system.scheduler, maxFailures = 5, callTimeout = 10.seconds, resetTimeout = 1.minute). onOpen(notifyMeOnOpen()) def notifyMeOnOpen(): Unit = log.warning( "My CircuitBreaker is now open, and " + "will not close for one minute")
system.scheduler().scheduleOnce( Duration.create(50, TimeUnit.MILLISECONDS), testActor, "foo", system.dispatcher(), null )
ExecutionContext
future
method which starts an asynchronous computation
and returns a future. The result becomes available once the future
completes.
import scala.concurrent.{ future, promise } import scala.concurrent.ExecutionContext.Implicits.global val s = socialNetwork.createSessionFor("user", credentials) val f: Future[List[Friend]] = future { s.getFriends() // may take a while }
success
, failure
, complete
import scala.concurrent.{ future, promise } import scala.concurrent.ExecutionContext.Implicits.global val p = promise[T] val f = p.future val prdcr = future { // producer val r = produceSomething() p . success . r continueDoingSomethingUnrelated() } val cnsmr = future { // consumer startDoingSomething() f . onSuccess { case r => doSomethingWithResult() }}
ActorSystem.actorOf
method and then …
ActorContext.actorOf
.
ActorSystem.actorSelection
method
Identify
message, to the
actor and use the sender
reference of a reply from the actor.
actorFor
is deprecated in favor of actorSelection
because actor
references acquired with actorFor behave differently for local
and remote actors. Beware: actorOf vs. actorSelection vs. actorFor
context.actorSelection("../*") ! msg
context . actorSelection ("../brother") ! msg
context.actorSelection("/user/serviceA") ! msg
akka { actor { provider = "akka.cluster.ClusterActorRefProvider" ... } extensions = ["akka.cluster.Cluster"] cluster { seed-nodes = [ "akka://ClusterSystem@127.0.0.1:2551", "akka://ClusterSystem@127.0.0.1:2552" ] auto-down = on } }
What Does "Finished" Mean? The most natural answer to this question appears to be, "When all the Mailboxes are empty." Natural, yes; correct, no. :)
import akka.actor.{Actor, ActorRef, Terminated} import scala.collection.mutable.ArrayBuffer object Reaper { case class WatchMe(ref: ActorRef); } abstract class Reaper extends Actor { import Reaper._ val watched = ArrayBuffer.empty[ActorRef] /* Derivations must implement this method. Called * when everything is dead */ def allSoulsReaped(): Unit final def receive = { case WatchMe(ref) => context.watch(ref) watched += ref case Terminated(ref) => watched -= ref if (watched.isEmpty) allSoulsReaped() } }
spray
is an open-source toolkit for building
REST/HTTP-based integration layers on top of Scala and Akka. Being
asynchronous, actor-based, fast, lightweight, modular and testable
it's a great way to connect your Scala applications to the world.
ssh
to Laptop/OSIS Lab machine 130.108.17.112
% /usr/local/activator-1.1.1/activator ui -Dhttp.address=130.108.17.112 -Dhttp.port=8080 -Dbrowser=/usr/bin/google-chrome
~/.activator/
and ~
// application.conf at the root of the class path. akka { loggers = ["akka.event.slf4j.Slf4jLogger"] loglevel = "DEBUG" stdout-loglevel = "WARNING" actor { provider = "akka.cluster.ClusterActorRefProvider" default-dispatcher { # set to 1 for as fair as possible throughput = 10 } } remote { netty.tcp.port = 2552 } }