Akka, dropping earlier messages - scala

I would like to drop earlier messages from an actor. The base idea is to have a timestamp on each message, store it for the last processed message message and drop messages earlier than this timestamp.
I am thinking to create mailbox for that, however I don't know:
If it is a good idea to keep a state in a mailbox.
How I can share the state of the actor (that has the timestamp) with the mailbox.
Maybe I am trying to something wrong and there is a better alternative for that ?
Thanks

Writing a custom mailbox for that is overkill. You can solve it like this:
class MyActor extends Actor {
val timestampLimit: LocalDateTime = ???
def receive = {
case m: Message if (m.getTimeStamp.isBefore(timestampLimit)) => // drop
case m: Message => // process
}
}

Related

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

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()
}

Play WebSocketActor createHandler with custom name

I am using (learning to) handle websockets in play application.
My controller is using WebSocket.acceptWithActor
def clientWS = WebSocket.acceptWithActor[JsValue, JsValue] { _ =>
upstream => ClientSesssionActor.props(upstream)
}
and all is well except some other "supervisor" actor needs to be able to use context.actorSelection(...) to communicate with all/some of those ClientSessionActors.
But all my ClientSessionActors are created with a path like this one :
[akka://application/system/websockets/ REQ_ID /handler]
Here is the line where WebsocketActorSupervisor creates them :
val webSocketActor = context.watch(context.actorOf(createHandler(self), "handler"))
That is where the "handler" part of the path comes from.
I would like to pass in a specific name for my ClientSessionActor instead of getting "handler".
Overloading the whole call stack with one more parameter seems inelegant: there is WebSocketActor.scala with Connect, WebSocketActorSupervisor(props and constructor), WebSocketsActor receive and then everything inside the WebSocket.scala.
I know I can pass the supervisor reference to the props, but what about the case when the "supervisor" has been restarted and needs to reconnect with his minions.
One more thing, I realize that I might be able to get all the "handler" actors, but there are more than 2 kinds of handlers. Yes I could have them ignore msgs directed at the other groups of handlers but this just feels so redundant sending out 3 times more msgs than I should have to.
Any suggestions ?
James ? :)
Thank you
How about each ClientSesssionActor sends a Register message to supervisor on preStart and store them in eg. val sessions = new HashMap[String, ActorRef].
And then unregister by sending Unregister in postStop
private class WebSocketsActor extends Actor {
import WebSocketsActor._
def receive = {
case c # Connect(requestId, enumerator, iteratee, createHandler) =>
implicit val mt = c.messageType
context.actorOf(WebSocketActorSupervisor.props(enumerator, iteratee, createHandler),
requestId.toString)
}
}
Here is code how play creates actors for handling websockets, it names with requestId.
I have also same question :) why not make it to name with custom names.

Where to shutdown actors

we have a lot of actors that get created as
class BankActor extends Actor{
def receive ={
case CreateCustomer(message) => context.actorOf(Props[CustomerActor]) ! message
}
}
And CustomerActor creates other actors in a similar manner. Reason for creating actors in such a way is potentially there will be hundreds(or even thousands) of CreateCustomer messages that BankActor will be receiving in them. I thought creating them on the fly is a better way (given Actor is a low memory footprint). I didn't think having a "pool" of CustomerActor was a right thing to do because biz req is clear there will be lots and lots of "CreateCustomer" messages. can you share your thoughts on this? Now going back to question about stopping "CustomerActor" : where should I be doing context.stop(self) inside "CustomerActor"'s "receive" method, should it be the last thing in every "case" block in there? What's the best practice around this?
Avoid creating top-level actors unless you have a good reason to. (Use context.actorOf)
Send the newly created actor a PoisonPill after the "message" if you don't want to encode the shutdown within the created actor.
class BankActor extends Actor{
def receive = {
case CreateCustomer(message) =>
val customer = context.actorOf(Props[CustomerActor])
customer ! message
customer ! PoisonPill // message ordering is preserved on a per-sender basis (for all normal mailboxes)
}
}

Akka - how to know if a message is a tell or an ask?

Is there any way to determine if a message is a tell or an ask?
Use case:
I'm seeing cases where a library is used from outside of an actor and tells are used for the message. Because the library will reply with the result for success/failure, yet me don't care about it in the usage, we're using tell and receiving back a message to a context that isn't an actor. By default the message goes to deadLetters which is fine but it logs the message. You can adjust the logging to shut up the messages but I'm wondering if there is any way to determine if the message is a tell or an ask from inside the library without doing something like having a specific message type for fire and forget vs asks.
I always include a "reply-to" field in my message types. Sometimes I make it an Option[ActorRef] but often I use a repeated parameter (which generalizes the response transmission and makes all cases cleaner–no None / Some(replyTo) / List(replyOne, replyTwo …) etc.) The repeated parameter approach is facilitated by an implicit class that allows fanout by providing a !* method.
So, something like this:
case class Req(i: Int, s: String, replyTo: ActorRef*)
case class Resp(mesg: String)
class MyActor extends Actor {
...
def receive = {
case Req(i, s, replyTo) => ... replyTo !* Resp("Consider it handled")
...
}
...
}

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 !