How to supervise actors in Akka and handle exceptions - scala

I am trying to improve the error handling with the actors in my system. Sometimes, when processing data, something goes wrong, and I need to stop and restart the actor, as well as log some information regarding this failure.
I have a Supervisor, which has 5 actors working for it. So I need to be able to supervise all of them. I found this link:
https://doc.akka.io/docs/akka/current/typed/fault-tolerance.html
regarding this, but I don't think it is very clear on where to implement the code:
Behaviors.supervise(behavior).onFailure[IllegalStateException](SupervisorStrategy.restart)
Where exactly is this code supposed to go?
Thanks

You can think of this supervisor as another behavioiur which wraps your behaviour inside of it.
Lets say you want to have following HelloWorld actor.
object HelloWorldActor {
sealed trait Command
case class HelloCommand(name: String) extends Command
def apply(): Behavior[Command] =
Behaviors.receiveMessage[Command] {
case msg: HelloCommand =>
println(s"Hello ${msg.name}")
Behaviors.same
}
}
Now, you can "wrap" this "behaviour" with a "supervisor"
object SupervisedHelloWorldActor {
sealed trait Command
case class HelloCommand(name: String) extends Command
def apply(): Behavior[Command] =
Behaviors.supervise(
Behaviors.receiveMessage[Command] {
case HelloCommand(name) =>
println(s"Hello ${name}")
Behaviors.same
}
).onFailure(onFailure[IllegalStateException](SupervisorStrategy.restart))
}

Related

Is there any way to map a Behavior from one type to another

I have a scenario where I need to provide a Behavior of a specific type. This Behavior also needs to handle events that are published on the Event Stream. So say the specific type is:
case class DoSomething(i: Int)
and I then need to implement a function to return a Behavior to handle this type of message:
def foo(): Behavior[DoSomething]
I then also need to handle the following message on the event stream:
case class PublishedEvent(str: String)
The only solution I came up with was to spawn another actor from within my DoSomething behavior and then forward messages to it:
sealed trait Command
case class Command1(str: String) extends Command
case class Command2(str: String) extends Command
def foo(): Behavior[DoSomething] = Behaviors.setup { context =>
val actor = context.spawnAnonymous[Command](Behaviors.setup { context =>
context.system.eventStream ! EventStream.Subscribe(context.messageAdapter {
case PublishedEvent(str) => Command2(str)
})
Behaviors.receiveMessage {
case Command1(str) =>
println("Received Command1: " + str)
Behaviors.same
case Command2(str) =>
println("Received Command1: " + str)
Behaviors.same
}
})
Behaviors.receiveMessage {
case DoSomething(i) =>
actor ! Command1(i.toString)
Behaviors.same
}
}
My question is is there any means of avoiding spawning a new actor and doing it all from within the same actor? i.e. Is there a way I can map a Behavior[Command] to a Behavior[DoSomething]?
I also have this problem regularly and the best solution I found is to use the narrow[...] method on a common "super Behavior" to narrow down on a message type a client is supposed to send to the respective actor. It is possible to combine the handling of both message types in one Behavior by defining a common interface (in scala of course a trait):
sealed trait CommandOrDoSomething // #TODO find better name
final case class DoSomething(i:Int) extends CommandOrDoSomething
sealed trait Command extends CommandOrDoSomething
case class Command1(str: String) extends Command
case class Command2(str: String) extends Command
def getBehavior(): Behavior[CommandOrDoSomething] = Behaviors.setup { context =>
Behaviors.receiveMessage {
// handle all kinds of messages here
}
}
Now, if you want to pass a Behavior[DoSomething] to a client, you can simply obtain it like this:
def foo(): Behavior[DoSomething] = getBehavior().narrow[DoSomething]
You can keep the Command trait private to your current context, but I think you will have to expose at least the common super trait to the outside world. With union types as they will be available in Scala 3 this can be avoided and you won't need the artificial super trait.
The docs (as well as the signature) indicate that transformMessages on Behavior would work, provided that the externally sent messages map 1:1 to internal messages:
def transformMessages[Outer: ClassTag](matcher: PartialFunction[Outer, T]): Behavior[Outer]
i.e. an actor materialized with Behavior[T].transformMessages[Outer] { ??? } will yield an ActorRef[Outer]
sealed trait External
case class DoSomething(i: Int) extends External
private sealed trait Internal
private case class Command1(str: String) extends Internal
private case class Command2(str: String) extends Internal
private def internalBehavior: Behavior[Internal] = Behaviors.setup { context =>
// do stuff with context
Behaviors.receiveMessage {
case Command1(s) => ???
case Command2(s) => ???
}
}
import akka.actor.typed.Behavior.BehaviorDecorators
def externalBehavior: Behavior[External] =
internalBehavior.transformMessages {
case DoSomething(i) => Command1(i.toString)
}
In this case, the internal commands are invisible outside of their scope. The main potential drawback I see (beyond the slight ickiness of bringing a PartialFunction into typed) is that within an actor with Behavior[Internal], you can't get the ActorRef for actor's external "personality", unless you have something crazy like
case class DoSomething(i: Int, recipient: ActorRef[External]) extends External
private case class Command1(str: String, externalPersonality: ActorRef[External]) extends Internal
It's worth noting that in the case where the internal messages are under your control, the 1:1 restriction can be worked around.

Scala: How to extend an Akka actor?

I wrote an Akka base-actor that can handle some common messages. I want to reuse this basic behavior in a sub-actor, by extending the base-actor (not by composition of the base-actor).
I have seen several approaches in previous questions. They are all valid but also may be improved:
How extend behaviour of super actor in akka
and
How do I best share behavior among Akka actors?
To make the implementation cleaner, I am trying to achieve the following:
When defining the sub-actor, I try to extend only the base-actor (not both Actor and sub-actor). However, I was not able to force the compiler to do this.
I also try to not rename the receive partial function, because it is a kind of convention.
Here is a sample of my implementation:
//This is the base-actor that implements the common behavior
trait BetterActor extends Actor {
abstract override def receive = {
super.receive orElse { case _ => println("Missing pattern!") }
}
}
//This is the actor that implements the additional behavior.
//I actually wanted to extend BetterActor. It was not possible.
class MyActor extends Actor {
def receive = {
case i: Int =>
println(s"Yay!!! Got $i")
}
}
Here are two alternative ways how I can create an instance of the sub-actor, which combines both the common and the additional behaviors:
//1.
val myBetterActor = system.actorOf(Props(new MyActor with BetterActor), "myBetterActor")
//2.
class MyBetterActor extends MyActor with BetterActor
val myBetterActor = system.actorOf(Props[MyBetterActor], "myBetterActor")
Finally, I may invoke the sub-actor by:
myBetterActor ! 2
myBetterActor ! "a"
Problems with my implementation:
When I create an instance of the sub-actor, only then I can mix in the base-actor, either directly (1) or by defining a new class that mixes in the base-actor.
Like I said before, I would prefer to mix in the base-actor when I define the sub-actor. Not when I try to create an instance of the sub-actor.
P.S. It's fascinating that the designers of this framework did not see it necessary to make this common requirement easy to accomplish.
i suppose as long as you're not trying to override behavior with BetterActor, you could try something like this:
trait BetterActor extends Actor {
override def unhandled(message: Any): Unit = message match {
case e: CommonMessage => println("COMMON!")
case e => super.unhandled(e)
}
}
class MyActor extends BetterActor {
override def receive = {
case i: Int => println(s"Yay!!! Got $i")
}
}

How to properly test actor behavior in case of failure

It is very important to know how a system might behave in case a particular actor fails - how does the recovery run, are the snapshots fetched properly etc. Surprisingly, I have not found any advice on it in the docs
An approach I have seen in some examples is to have a special Fail msg and let the actor throw an Exception on this msg.
class MyActor extends Actor {
override def receive =
...
case Fail => throw new Exception("kaboom")
}
I hope never to use it as it mixes production code and test code and would probably generate some reasonable WTFs in unsuspecting readers.
How would I induce an arbitrary actor to fail properly?
Thank you
After some thought, I have implemented a quick solution. The test package contains a trait for failing which is then mixed into actors for failure testing:
object Failing{
case object Fail
}
trait Failing {
def failOnMsg: PartialFunction[Any, Unit] = {
case Fail => throw new Exception("kaboom!")
}
}
then in the test the PF is prepended to the original receive
val props = Props(new MyActor(arg) with Failing {
override def receive = failOnMsg orElse super.receive
})
val actor = system.actorOf(props)
actor ! Fail
It is still better than what I had before, but brings some boilerplate. I hope there is a better solution.

how to add logging function in sending and receiving action in akka

Now, I am asked to add logging function in akka's actor.
When a message is received, before it is handled, this message should be written into log.
And before a message is sent out, this message should be logged first.
I think I should override the receive and send functions in Actor. Suppose I create a trait actorlog which extends Actor. And class myActor extends actorlog. But in myActor, I need to override receive function (it seems it causes problems here). So I am confused what I should do.
PS. I know akka provides logging. But now I need implement this function by myself.
There is a utility to get logging of the received messages in Akka. It's briefly mentioned in the logging documentation. Basically you wrap your receive function in it like this:
def receive = LoggingReceive {
// your normal receive here
}
And then you enable it in your config with:
akka.actor.debug.receive=on
The information will be logged at debug level.
Besides the other answers here, another approach is to use orElse to prepend a partial function to your receive. In that partial function, put the logging in isDefinedAt so it gets called on every message.
For example:
trait ReceiveLogger {
this: Actor with ActorLogging =>
def logMessage: Receive = new Receive {
def isDefinedAt(x: Any) = {
log.debug(s"Got a $x")
false
}
def apply(x: Any) = throw new UnsupportedOperationException
}
}
class MyActor extends Actor with ActorLogging with ReceiveLogger {
def receive: Receive = logMessage orElse {
case ...
}
}
Using orElse is a general approach for composing receive behavior. In most cases I am composing things like this:
def otherBehavior: Receive = {
case OtherMessage => ...
}
class MyActor extends Actor {
def receive = otherBehavior orElse {
case ...
}
}
A good example of the stackable traits approach can be seen in this presentation: http://www.slideshare.net/EvanChan2/akka-inproductionpnw-scala2013
use stackable modificator abstract override for stackable call of receive method.
use new feature of Akka: event-sourced actor system (docs here).

How can we override the react construct of scala actors?

The usual way of detecting the type of message received in scala actors is by
loop{
react{
case x: String =>
}
}
However, I want to know how can we override this implementation of react construct so that we can do implicit logging of the message that is received.
I am trying to implement a use case mentioned below ->
1. Before a message is matched to any case class, I want to write a log statement on console / file showing the occurance of the message.
2. We can log these messages explicitly by println() / log4j logging . However, I want to design a generic logger for scala actors which will log all the messages sent or received.
Any help in this regard will be helpful.
Thanks in advance
First, be aware that the Scala actors library is being deprecated in favor of Akka. So this answer won't be helpful very long (though the other actors library will continue to be available for a while--and since it's open source potentially forever if people want to maintain it).
Anyway, the react method is defined in scala.actors.Actor. Simply fail to import it, or hide it with your own. Your own what?
Well, the method just takes a PartialFunction[Any,Unit]. So, your should also:
def react(pf: PartialFunction[Any,Unit]): Nothing = { /*how?;*/ Actor.react(/*what?*/) }
You really only have access to the partial function, and you have to defer to Actor.react to do what you want. So you need to wrap pf in another PartialFunction that performs your logging. So you can
val qf = new PartialFunction[Any,Unit] {
def isDefinedAt(a: Any) = pf.isDefinedAt(a)
def apply(a: Any): Unit = {
log(a) // Maybe add more logic to know what a is
pf(a)
}
}
If you want to see messages that come in and get examined but are not actually consumed, you could do more with isDefinedAt also.
So, obviously enough, I hope, /*how?*/ is the above to define (create) qf, and /*what?*/ is just qf.
If you want to know whether a is a case class, the answer is that you cannot (by design). A case class is just syntactic sugar on top of ordinary Scala features; it's just there to save you typing. See, for instance, this question.
However, you can get pretty close by pattern matching for Product and checking whether it has a copy method:
case class M(i: Int)
val a: Any = M(5)
scala> a match {
case p: Product if p.getClass.getMethods.exists(_.getName=="copy") => println("Yes")
case _ => println("No")
}
Yes
If you really want to get fancy, check if copy has the same number and type of parameters as the constructor.
//Following is a code for a logReact Method that does the same thing as react but also logs the message received hope this works for you
import scala.actors.Actor;
import scala.actors.Actor._
trait ActorLogging extends Actor {
def logReact(handler: PartialFunction[Any, Unit]): Nothing = {
val handler2: PartialFunction[Any, Unit] = {
case x =>
println("Inside Logs -- with message recieved -- " + x.toString);
handler.apply(x);
}
super.react(handler2)
}
}
class sumAct extends Actor with ActorLogging {
def act() {
loop {
logReact {
case a: Int =>
println("Inside actor Sum Act Received the message -- " + a)
exit;
}
}
}
}
object ActorLog {
def main(args: Array[String]): Unit = {
var s: sumAct = new sumAct;
s.start();
s ! 1.toInt;
}
}