Akka is a toolkit and runtime whose focus is on simplifying the creation of concurrent and distributed
systems.
Akka is most commonly associated with their actor library.
However, Akka Platform comprises several modules and libraries:
Akka's success comes primarily from bringing the Actor Model (highly inspired by the Erlang one) to the JVM.
Actors organize themselves in parent-children hierarchies. Each parent takes care of their children during their complete lifetime.
“One Actor is no Actor. Actors come in Systems.”
Carl Hewitt
Actors can only communicate with each other using messages. Any attempt to access directly their internal state is against the Actor Model.
Ideally such messages should be immutable.
Overly simplifying an actor encapsulates:
* Optional
An Actor that doesn't keep any kind of state, most probably is not an Actor.
Akka Actors provide concurrency safety in regards of their state, meaning, it can be modified without worrying about concurrency issues.
A behavior is how an actor handles messages. In the end, it is a function that takes a message as an argument and performs some given actions accordingly.
An actor's behavior can be dynamically changed.
All messages sent to an Actor are first stored in their mailbox until they can be processed.
One can tune the actor by choosing different types of Mailboxes.
Optionally, an Actor can create children to delegate subtasks to them. Unlike in real life, their lifetime is controlled by the parent.
Set of rules that define how to react in front of exceptions:
An ActorRef
is the "address we send the messages". It encapsulates the internals of an
actor and
it's their external representation.
If you can solve your problem with a Future
, probably you won't need Actors.
Nowadays, Actors are the lowest level of abstraction on the Akka ecosystem. There might be higher abstractions that would fit better to your use case.
For example Akka Streams and Akka HTTP.
type Receive = PartialFunction[Any, Unit]
The main criticism to Akka Actors has always been the lack of any types on their Actors.
import akka.actor.{Actor, Props}
import io.github.jlprat.akka.lnl.intro.classic.MiniExample.{Click, RetrieveClicks}
object MiniExample {
sealed trait Command
case object Click extends Command
case object RetrieveClicks extends Command
def props(): Props = Props(classOf[MiniExample])
}
class MiniExample extends Actor {
var clicks: Long = 0
override def receive: Actor.Receive = {
case Click => clicks = clicks + 1
case RetrieveClicks => sender() ! clicks
}
}
import akka.actor.{Actor, Props}
import io.github.jlprat.akka.lnl.intro.classic.MiniExampleBecome.{Click, RetrieveClicks}
object MiniExampleBecome {
sealed trait Command
case object Click extends Command
case object RetrieveClicks extends Command
def props(): Props = Props(classOf[MiniExampleBecome])
}
class MiniExampleBecome extends Actor {
override def receive: Actor.Receive = clickCounting(0)
private def clickCounting(count: Long): Actor.Receive = {
case Click => context.become(clickCounting(count + 1))
case RetrieveClicks => sender() ! count
}
}
Since Akka 2.6.x
a new type of Actors is available and production ready.
import akka.actor.typed.{ActorRef, Behavior}
import akka.actor.typed.scaladsl.Behaviors
object MiniExample {
sealed trait Command
case object Click extends Command
case class RetrieveClicks(replyTo: ActorRef[Long]) extends Command
def apply(): Behavior[Command] = counting(0)
private def counting(count: Long): Behavior[Command] =
Behaviors.receiveMessage {
case Click => counting(count + 1)
case RetrieveClicks(replyTo) =>
replyTo ! count
Behaviors.same
}
}
There are two different modes for testing: Synchronous and Asynchronous.
Typically asynchronous testing is the preferred one, leaving synchronous testing for the pure unit tests.
It replicates a "live environment" and offers out of the box probes and mocking capabilities. It works for advanced Akka features like Timers and Clustering.
On Akka Typed
it's independent from the ActorSystem
and is useful to test Actors in
isolation.
On Akka Classic
, this type of testing is not actively encouraged, but it's still useful to check
the side effects
caused by the processing of a message.