How to receive a message within a specific case of a receive in Akka actors? - scala

I am trying to implement an Akka actor which receives a message and then waits to receive another message without looping. The reason that I am trying to implement it this way is because I require the object received in the first case statement in the second case statement. Below is an example of what I mean.
def receive: Receive = {
case s # start =>
receive {
case e # end =>
println(f"Received ${s} and ${e}")
}
}
I am aware that this might not be the ideal pattern. However, I am still new to Akka and Scala and am not aware of any other way to implement this. All suggestions are welcome.

This is a good way to achieve this:
Create a second receive method that just waits for the second message. Use context.become to set this method as the receive function when the first message arrives. The s value can be a parameter of this method.
When the second message arrives, it is handled by the new receive method. Use context.become to restore the original receive method once the message is processed.
You can use the Stash support to stash any other messages that come when the second receive method is active. When an unexpected message arrives, stash the message. When the correct message has been processed and the original receive handler has been restored, call unstashAll to put them back on the queue. These messages will be re-sent to the actor in the original order to be processed by the main receive method.
It might look like this:
def receive: Receive = {
case s # start =>
context.become(endReceive(s))
// Other cases
}
def endReceive(s: ???): Receive = {
case e # end =>
println(f"Received ${s} and ${e}")
context.become(receive)
unstashAll()
case _ =>
stash()
}

Related

How to test if an Actor is able to receive the message or not?

I have the below Actor which receives two messages:
class SampleActor extends Actor {
def receive = {
case "hello" => println("Hello Message")
case "world"=>println("World Message")
case _=>println("Unhandled message")
}
}
}
I want to test if the actor is able to receive the messages "hello" and "world". The examples I have seen do not fulfill this requirement.
The one here and here has the actor sending back a message and using expectMsg() they check the response. But my requirement is to see if the Actor is able to receive the message or not, and not whether the actor is able to respond back with a specific message.
The example here changes the state of the actor and they check the state to see if the actor is able to receive the message. Again, not what I wanted.
So, how do I just test if my actor is able to handle the two messages through TestKit?

Sending back to sender, from supervisor, in case of failure

I have an Actor, which acts as a Supervisor, but also needs to "return" data to the caller, wether this is an actor or not shouldn't matter.
I am asking my Supervisor, let's call him SV.
SV Processes the message I send to him, and sends back a response.
val system = ActorSystem("ActorSystem")
val sv = system.actorOf(Props[SV], name = "SV")
sv ? msg
And SV's recieve method looks like this:
def receive = {
case msg => (someChild ? msg).pipeTo(sender)
...
}
This all works jolly fine.
The problem is when the child throws an exception, this exception is caught by the supervisor strategy.
override def supervisorStrategy = OneForOneStrategy () {
case e : Throwable => {
val newResponse = someNewResponse
sender ! newResponse
...
}
}
sender is not longer a reference to whoever called SV in the first place, and I can't seem to work out how to send a message back to the askee, and get back to my original flow.
One of the three Actor rules is: “An Actor can send a finite number of messages to other Actors it knows.” The last two words are critical here: if the supervisor has not been introduced to the original sender somehow and the failure (exception) itself does not contain the sender’s reference either, then the supervisor cannot possibly send a message to the sender. Either you catch all exceptions in the child actor, wrap them together with the sender in your own exception type and then rethrow, or the original message needs to travel via the supervisor to the child and back, so that the supervisor can see that a reply is outstanding when a failure occurs.
Are you using the supervisor strategy and exceptions to control the flow or your data? Consider using the type system (Option type or a Failure on the response Future) for "exception" cases in your child actors and handle the response flow without exceptions.
The supervisor strategy is for unhandled exceptions.
When an unhandled exception occurs you lose the ability to respond with a message to the sender. Unless you wrap the sender in the unhandled exception like Roland Kuhn suggests.
Let the supervisor strategy instead handle how the actor system should respond to your unhandled exceptions by mapping them to a Directive.

Capturing the message that killed an actor

I'm trying to respond to the sender of message when the receiving actor dies due to that message. If I Restart the actor on failure I get
preRestart(reason: Throwable, message: Option[Any])
but now I'm committed to restarting.
If I Stop the actor, i only get
postStop()
with no knowledge what stopped myself.
Meanwhile in the supervisor, I only get the Throwable and no indication of what caused it.
I suppose, I can dig through the DeadLetters post actor termination, but that seems like a noisy approach, since I'd have to listen to all of dead letters and somewhere correlate the termination with the deadletter event stream.
UPDATE: DeadLetter really doesn't seem to be an option. The message that caused the death doesn't even go to DeadLetters, it just disappears.
Is there a mechanism I am overlooking?
According to this thread on the Akka Users List, there isn't a mechanism in the actor supervision death cycle to accomplish this. Moreover, the documentation explicitly states that the message is dropped:
What happens to the Message
If an exception is thrown while a message is being processed (i.e. taken out of its mailbox and handed over to the current behavior), then this message will be lost. It is important to understand that it is not put back on the mailbox. So if you want to retry processing of a message, you need to deal with it yourself by catching the exception and retry your flow.
The ideal solution would be to use a dedicated actor for dangerous operations and have the initiator monitor the death of that actor to determine failure.
As my scenario arose from something considered safe but that had a bug in it, the separate actor option would have been after the fact. To avoid wrapping all code paths in try/catch but be able to guard more complicated and critical flows, I ended up with creating a wrapper for receive that let's me intercept exceptions:
object SafeReceive {
def apply(receive: Receive)(recover: Any => PartialFunction[Throwable, Unit]): Receive =
new Receive {
override def isDefinedAt(x: Any): Boolean = receive.isDefinedAt(x)
override def apply(v1: Any): Unit = try {
receive(v1)
} catch recover(v1)
}
}
which I can use for select actors like this:
def receive = SafeReceive {
case ... => ...
} {
msg => {
case e: Exception =>
sender ! OperationFailed(msg, e)
throw e
}
}

Akka and java.nio. Non-blocking selector

I'm trying to write server which listen for tcp connection.
I'm using nonblockig java.nio.
My selector.select() starts when actor receive "STARTLISTEN" message and it's ok, but when i sent messages to actor it not receive messages until selector not received any data.
How to avoid this? For example i want to send message "STOP" to my actor to stop selecting?
Is only way to call select with timeout or selectNow()?
I'm not going to use akka.io.
It's not full code but it illustrates the problem:
class MyActor(val host: String, port: Int) extends Actor {
val serverChannel = ServerSocketChannel.open()
val channelSelector = Selector.open()
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress( InetAddress.getByName(host), port ))
serverChannel.register(channelSelector, SelectionKey.OP_ACCEPT);
override def receive = {
case "STARTLISTEN" => {
val keys = channelSelector.select()
// processing read write etc....
}
case "STOP" => {
// I want to stop selection here....
}
}
}
Even though you dismiss it out of hand, I’d like to point out (on the record) that using the proven implementation of exactly this which ships with Akka already is probably the better way to go. (I’m linking to the 2.3.0-RC2 documentation because some of the experimental features which were introduced in the 2.2.x series will not be part of Akka going forward—survival of the fittest.)
You might be able to accomplish this by splitting your actor into multiple actors. The first actor receives messages from outside, and the second blocks on select(). The first actor can use wakeup() to stop the second from blocking before sending it any messages.

Any way of appending to the act method in scala?

First off, I am new to Scala:
I am writing a logging facility in Scala that will simply be a class that extends the Actor class. This way a user can just extend this class and the logging features will be available. Basically, I want to write to a log file every time an actor that extends this class sends or receives a message. For clarification every actor will have its own log file which can be collated later. I am taking a Lamport clocks style approach to ordering the events by having each Actor (who extends this class) have their own time variable that gets updated on a message send-receive and the actor will compare the current time variable (simply a positive integer) with the sender's and update its time variable with the greater of the two.
For now I chose to make it a simple method like
sendMessage(recipient, message)
For sending messages. This will just log to the file that the actor is going to send a message to X.
Now, the part that I am stumped on is doing logging when receiving messages. When an actor gets a message I simply want to log this event in a format like
myLogFile.writeLine(self.ToString+": Got a message from "+X+" at time: "+messageSendTime+", processed the message at" +Math.max(myCurrTime+1, messageSendTime+1))
However I need to know who sent this message, unless I force upon the user to include this info (namely the sender's name, time variable, etc) in the messages themselves, it gets hard(er). Is there any way to get the reference of the actual sender? I want this to work with remote actors as well. The only way I can think of is if I append to the act method that the user defines in his/her class with some extra case statements like:
def act {
case => // the user's case statements
...
//somehow I append these statements to the end for the Logger class's use
case (LoggerClassRegisterInboundMessage, message, timeStamp)
InboundMessagesMap.put(timeStamp, message)
}
By having this functionality I can do all the logging "behind the scenes" with these hidden messages being sent whenever the user sends a message. However this only works if the sender also uses the Logging facility. So a more general question is: is there a way in Scala to get the name/toString of a sender in Scala regardless of the sender's class?
I'm actually OK with going with the assumption that every class that sends messages will extend the Logger class. So if anyone knows how to append to the act like or something similar to the above example I will be equally grateful!
As it was said in the comments, Akka is the way to go. It's so much more powerful than the current Scala Actor API which will become deprecated with 2.10 anyway.
But, to attack your specific problem, you could create a trait for actors which support logging, in a way similar to this (I don't know if this actually works, but you can try it):
trait LoggingActor extends Actor {
override def receive[R](pf: PartialFunction[Any, R]): R = {
//we are appending to the partial function pf a case to handle messages with logging:
val loggingPf = pf orElse {
case (LoggerClassRegisterInboundMessage, message, timeStamp) => {
//do somthing with this log message.
message //returning the unwrapped result afterwards
}
}
super.receive(loggingPf)
}
//overriding the send as well
override def !(msg: Any): Unit {
//Wrap it in a logging message
super ! (LoggerClassRegisterInboundMessage, msg, getTimestamp())
}
}
And you would create your actors with something like this:
val myActor = new MyActor with LoggingActor
Hope it helps !