This document discusses using Akka and actors for building scalable and concurrent applications in Scala. It introduces actors as fundamental units of computation that communicate asynchronously via message passing. Akka provides tools for creating actor systems and hierarchies. The document uses a monitoring application called Scotchdog as an example, with actors to represent services that are monitored by a watchdog actor. It describes how messages are used to start, stop and check services, and how the watchdog can aggregate status from child actors. The document also briefly mentions using Akka's scheduler and finite state machines to implement more complex actor behaviors.
4. SCALA
• Programming language for JVM
• Functional and Object-Oriented
• Type-safe
• Powerful
• Concise
• Extensible
• Interoperable with Java
5. AKKA
• Akka is a toolkit and runtime for building
highly concurrent, distributed, and fault
tolerant event-driven applications on the JVM
• Provides unified programming model for
concurrency, distribution and fault-tolerance
6. ACTORS
Actor is a fundamental unit of computation
(Carl Hewitt 1973)
• Local state, isolated from the world
• Sends messages to other actors
• Reacts to received messages
• Actors usually come in systems
7. ACTORS
• Elastic – grow and shrink on demand
• Lightweight (2.7 M per GB RAM)
• Hot deploy – change behavior at runtime
• Local or distributed
8. EXAMPLE - SCOTCHDOG
• Inspired by Monit
http://mmonit.com/monit/
• Cross-platform,
JVM-based (Scala+Akka)
• Configured with list of services
• Starts and stops services
• Ensures that monitored services are up:
checks periodically and starts if necessary
9. HOW IS THIS GOING TO WORK
• Actor per service
• Actor for the watchdog
11. AKKA ACTOR HIERARCHY
root
system user
Watchdog
system
actors
Service 1 Service 2 Service 3
12. WHY THE HIERARCHY IS IMPORTANT
• Fault-tolerance
• “Let it crash”
• Supervisor can resume, restart, terminate
the subordinate; it can also escalate the
failure
• One-for-one and one-for-all strategies
13. LET’S START WITH MESSAGES
• Service commands
• start
• stop
• is started?
• monitor/unmonitor
• Watchdog commands
• start
• add service
• do *** to a specified service
• …
14. SERVICE COMMANDS
sealed trait ServiceCommand
case object Start extends ServiceCommand
case object Stop extends ServiceCommand
case object IsStarted extends ServiceCommand
…
• Commands need to be immutable objects
• Case classes and objects make excellent messages
15. WATCHDOG COMMANDS
case object StartWatching
case class AddService(config: ServiceConfig)
case class PerServiceCommand(
service: String,
command: ServiceCommand)
...
16. SENDING MESSAGES
• tell (a.k.a bang, or ! operator) sends a
message asynchronously and return
immediately
service ! Start
• ask (a.k.a ? operator) sends a message
asynchronously and returns a Future
representing a possible reply
service ? IsStarted
17. HANDLING MESSAGES
• Define actor class
class Service(config: ServiceConfig) extends Actor …
• Actor gives us
• ability to create other actors
• access to self
• access to sender of last message
• lifecycle hooks
18. HANDLING MESSAGES
Define receive method within Actor class
def receive = {
case Start => //perform start action
case Stop => //perform stop action
case IsStarted => {
//call isStarted action and capture the result
sender ! result //reply - return the result to sender
}
}
Heavily uses Scala’s pattern matching
19. CREATING ACTORS
• class Watchdog extends Actor …
• val system = ActorSystem(“Scotchdog”)
• val watchdog = system.actorOf(
Props[Watchdog], name = “watchdog”)
• watchdog is an ActorRef
• we used default constructor
• Props allows customizations of actor
behavior, such as the dispatcher (execution
strategy). We used the default one
20. HANDLING MESSAGES - WATCHDOG
def receive = {
case AddService(config) => {
val service = context.actorOf(Props(new Service(config)),
config.name)
service ! Monitor
}
case PerServiceCommand(service, command) =>
context.actorFor(service) forward command
…
21. ACTOR REFERENCES
• Top level actors are created with
system, child actors are created with parent
actor’s context
• Existing actors can be found with
context/system actorFor
• ActorRef can be sent to another actor
22. FUTURES
val future = watchdog ?
PerServiceCommand(“myserver", IsStarted)
There are several ways to obtain the value:
• val result = Await.result(future, 5 seconds).
asInstanceOf[Boolean]
• future onComplete {
case Success(value: Boolean) => …
case Failure(_) => …
}
23. MORE ADVANCED EXAMPLE
• We want the watchdog to return a combined
status of all services – “up” if all services are
up, otherwise “down”
• We will define:
val services =
new scala.collection.mutable.HashSet[String]
within Watchdog class
• It is safe to have mutable state within an actor!
• When adding services: services += config.name
24. MORE ADVANCED EXAMPLE
def receive = {
case Status => {
val responses =
for (child <- services;
serviceActor = context.actorFor(child));
future = serviceActor ? IsStarted)
yield future.asInstanceOf[Future[Boolean]]
sender ! Future.reduce(responses)(_ && _)
}
…
25. SCHEDULER
• We want to check periodically if a service is
up, and report the status at any time
• For this purpose we can use Akka’s built-in
scheduler
• …
26. SCHEDULER EXAMPLE
class ServiceMonitor(config: ServiceConfig) extends Actor with ActorLogging {
var status = false
var polling: Option[Cancellable] = None
def receive = {
case IsStarted => sender ! status
case Monitor =>
polling = Some(scheduler.schedule(Duration.Zero, config.interval, self, Tick))
case Tick =>
sender ? config.isStarted onSuccess { case res: Boolean => status = res }
case UnMonitor => polling.foreach(_.cancel)
…
27. FURTHER IMPROVEMENTS
• In practice, the service actor is more
complex: for example, we don’t want to start
a service again if it is already started or is
starting up now
• To address this we use Akka’s Finite State
Machine actors, a.k.a FSM
• This is a topic for a longer talk, so for now…
28. CONCLUSIONS
• Akka makes concurrency (and
distribution, which we didn’t cover) easier
• Programming with actors require a paradigm
shift, may be challenging at first, but worth it
• There is more to Akka then we’ve covered
• If you like Akka, but want to program in
Java, you can use Java API
• Akka integrates with tools like Spring, Apache
Camel and ZeroMQ