Mutable collections in akka Actor return NullPointerException - scala

I have an actor which is calling a websocket and updating a map everytime it receives an update form the web socket. the same map is being used by the actor at another point in the command.
class MyActor(broker: InMemoryBroker) extends Actor {
val myMap: TrieMap[String, String] = new TrieMap[String, String]()
//Gets a response every 1 second
webSocket.get(onReponse= r=> myMap(r.key) = r.value)
def receive()={
case MyCommand(key)=>
if(myMap.get(key).isDefined){ //Null pointer exception is thrown here
//Do stuff
}
}
I was expecting TrieMap to be thread safe and not have such issues. Any suggestions?

You should do as much processing as possible in the receive method. So rather than updating the map directly in onResponse, send yourself a message and update the map when you receive it:
class MyActor(broker: InMemoryBroker) extends Actor {
val myMap: TrieMap[String, String] = new TrieMap[String, String]()
private case class UpdateMap(r: ???)
//Gets a response every 1 second
webSocket.get(onReponse = r => self ! UpdateMap(r))
def receive() = {
case UpdateMap(r) =>
myMap(r.key) = r.value
case MyCommand(key) =>
if (myMap.get(key).isDefined) { //Null pointer exception is thrown here
//Do stuff
}
}
}
With the method the TrieMap is only accessed from a single thread at a time.
Also, that test is better done as:
myMap.get(key).foreach{ value =>
???
}

Related

Scala akka typed: how to get ActorRef to Actor from it's instance and send message itself?

I want to send message from Actor instance (case class/class from what it's behaviour created) to it's Actor.
I gain it by saving instance, and then save ActorRef in it:
val (instance, behaviour) = MyActorInstance(Nothing)
val actor = ActorSystem(instance, "SomeName123")
//save it here
instance.setMyActor(actor)
object MyActorInstance {
def apply(ctx: ActorContext[Commands]): (MyActorInstance,Behavior[Commands]) = {
val actorInstance = new MyActorInstance(ctx)
val behaviour: Behavior[Commands] =
Behaviors.setup { context =>
{
Behaviors.receiveMessage { msg =>
actorInstance.onMessage(msg)
}
}
}
(actorInstance,behaviour)
}
}
class MyActorInstance(context: ActorContext[Commands]) extends AbstractBehavior[Commands](context) {
protected var myActorRef: ActorRef[Commands] = null
def setMyActor(actorRef: ActorRef[Commands]): Unit = {
myActorRef = actorRef
}
override def onMessage(msg: Commands): Behavior[Commands] = {
msg match {
case SendMyself(msg) =>
myActorRef ! IAmDone(msg)
Behaviors.same
case IAmDone(msg) =>
println(s"Send $msg to myself!")
Behaviors.same
}
}
}
Here i save ActorRef to Actor for it's instance in var myActorRef.
Then i use that myActorRef to send message from Actor's instance to itself by SendMyself message.
But for that, as you see, i am using variables, which is not good: to save ActorRef it's need to rewrite field myActorRef of instance of MyActorInstance class from null to ActorRef - it is possible only with variables.
If I try to use val and create immutable class by rewriting its instance for new, and then swap it from old to new, my Actor actor still linked to old instance where myActorRef == null.
Now I found one way: just using var instead of val or immutable class.
But I want to use val or nothing.
For that I need to get ActorRef from it's instance, but how?
There is no reason for such complex dance, just use ctx.self. And please read at least the most basic documentation before asking, it would even have saved you time.

when an actor contains an async method, this will lead to dead letter error with the Ask time out exception

I use ask mode send a request to an actor called actor-A in a function called fun-F. The actor will get an ID generated by another system in an async way, when this is completed, I will forward a message contains this ID to another actor called actor-B, the actor-B will do some DB operations and then send back the DB operation result in a message to the sender, since in my case I use forward mode, so the actor-B recognize the sender as fun-F, the akka will give the fun-F a temporary actor name, so the returned value should be delivered to the temp actor.
My question is:
If I use sync-method to get the ID from another system, then forward this message to the actor-B, after actor-B's DB operation, the result can be delivered to the value of fun-F, and the fun-F is defined as temporary actor Actor[akka://ai-feedback-service/temp/$b] by the akka framework runtime.
If I use async-method to get the ID from another system, when it completed, I will forward the message in the oncompleted {} code block in another call back thread, the DB operation in actor-B is handled successfully, but the returned value cannot be delivered to the value defined in the fun-F, and in this case the fun-F is defined as Actor[akka://ai-feedback-service/deadLetters] by the akka framwork runtime. So the actor-B lose its way and do not know how to get back or where should this message be delivered, and this will cause an Ask time out exception throws in my log.
How can I handled this issue? or how can I avoid this dead letter ask time out exception?
Below is my code:
// this is the so-called fun-F [createFeedback]
def createFeedback(query: String,
response: String,
userId: Long,
userAgent: String,
requestId: Long,
errType: Short,
memo: String): Future[java.lang.Long] = {
val ticket = Ticket(userId,
requestId,
query,
response,
errType,
userAgent,
memo)
val issueId = (jiraActor ? CreateJiraTicketSignal(ticket))
.mapTo[CreateFeedbackResponseSignal].map{ r =>
r.issueId.asInstanceOf[java.lang.Long]
}
issueId
}
//this is the so-called actor-A [jiraActor]
//receive method are run in its parent actor for some authorization
//in this actor only override the handleActorMsg method to deal msg
override def handleActorMsg(msg: ActorMsgSignal): Unit = {
msg match {
case s:CreateJiraTicketSignal =>
val issueId = createIssue(cookieCache.cookieContext.flag,
cookieCache.cookieContext.cookie,
s.ticket)
println(s">> ${sender()} before map $issueId")
issueId.map{
case(id:Long) =>
println(s">> again++issueId = $id ${id.getClass}")
println(s">>> $self / ${sender()}")
println("again ++ jira action finished")
dbActor.forward(CreateFeedbackSignal(id,s.ticket))
case(message:String) if(!s.retry) =>
self ! CreateJiraTicketSignal(s.ticket,true)
case(message:String) if(s.retry) =>
log.error("cannot create ticket :" + message)
}
println(s">> after map $issueId")
}
//this is the so-called actor-B [dbActor]
override def receive: Receive = {
case CreateFeedbackSignal(issueId:Long, ticket:Ticket) =>
val timestampTicks = System.currentTimeMillis()
val description: String = Json.obj("question" -> ticket.query,
"answer" -> ticket.response)
.toString()
dao.createFeedback(issueId,
ticket.usrId.toString,
description,
FeedbackStatus.Open.getValue
.asInstanceOf[Byte],
new Timestamp(timestampTicks),
new Timestamp(timestampTicks),
ticket.usrAgent,
ticket.errType,
ticket.memo)
println(s">> sender = ${sender()}")
sender() ! (CreateFeedbackResponseSignal(issueId))
println("db issue id is " + issueId)
println("db action finished")
}
To avoid the dead letters issue, do the following:
For every request, use an identifier (probably the requestId) that you can associate with the ultimate target for the request. That is, tie the requestId that you're passing to the createFeedback method to the caller (ActorRef) of that method, then pass this id through your messaging chain. You can use a map to hold these associations.
Change CreateFeedbackResponseSignal(issueId) to include the requestId from the Ticket class: CreateFeedbackResponseSignal(requestId, issueId).
When dealing with the asynchronous result of a Future from inside an actor, pipe the result of the Future to self instead of using a callback.
With this approach, the result of createIssue will be sent to jiraActor when the result is available. jiraActor then sends that result to dbActor.
jiraActor will be the sender in dbActor. When jiraActor receives the result from dbActor, jiraActor can look up the reference to the target in its internal map.
Below is a simple example that mimics your use case and is runnable in ScalaFiddle:
import akka.actor._
import akka.pattern.{ask, pipe}
import akka.util.Timeout
import language.postfixOps
import scala.concurrent._
import scala.concurrent.duration._
case class Signal(requestId: Long)
case class ResponseSignal(requestId: Long, issueId: Long)
object ActorA {
def props(actorB: ActorRef) = Props(new ActorA(actorB))
}
class ActorA(dbActor: ActorRef) extends Actor {
import context.dispatcher
var targets: Map[Long, ActorRef] = Map.empty
def receive = {
case Signal(requestId) =>
val s = sender
targets = targets + (requestId -> s)
createIssue(requestId).mapTo[Tuple2[Long, Long]].pipeTo(self) // <-- use pipeTo
case ids: Tuple2[Long, Long] =>
println(s"Sending $ids to dbActor")
dbActor ! ids
case r: ResponseSignal =>
println(s"Received from dbActor: $r")
val target = targets.get(r.requestId)
println(s"In actorA, sending to: $target")
target.foreach(_ ! r)
targets = targets - r.requestId
}
}
class DbActor extends Actor {
def receive = {
case (requestId: Long, issueId: Long) =>
val response = ResponseSignal(requestId, issueId)
println(s"In dbActor, sending $response to $sender")
sender ! response
}
}
val system = ActorSystem("jiratest")
implicit val ec = system.dispatcher
val dbActor = system.actorOf(Props[DbActor])
val jiraActor = system.actorOf(Props(new ActorA(dbActor)))
val requestId = 2L
def createIssue(requestId: Long): Future[(Long, Long)] = {
println(s"Creating an issue ID for requestId[$requestId]")
Future((requestId, 99L))
}
def createFeedback(): Future[Long] = {
implicit val timeout = Timeout(5.seconds)
val res = (jiraActor ? Signal(requestId)).mapTo[ResponseSignal]
res.map(_.issueId)
}
createFeedback().onComplete { x =>
println(s"Done: $x")
}
Running the above code in ScalaFiddle results in the following output:
Creating an issue ID for requestId[2]
Sending (2,99) to dbActor
In dbActor, sending ResponseSignal(2,99) to Actor[akka://jiratest/user/$b#-710097339]
Received from dbActor: ResponseSignal(2,99)
In actorA, sending to: Some(Actor[akka://jiratest/temp/$a])
Done: Success(99)

postRestart and preRestart methods are not getting invoke in akka actots

I am following this tutorial here is my code
case class ArtGroupDeleteFromES (uuidList:List[String])
class ArtGroupDeleteESActor extends Actor{
val log = LoggerFactory.getLogger(this.getClass)
override def preStart() {
log.debug("preStart Starting ArtGroupDeleteESActor instance hashcode # {}",
this.hashCode())
}
override def postStop() {
log.debug("postStop Stopping ArtGroupDeleteESActor instance hashcode # {}",
this.hashCode())
}
override def preRestart(reason: Throwable, message: Option[Any]) {
log.debug("I am restarting")
log.debug("ArtGroupDeleteESActor: preRestart")
log.debug(s" MESSAGE: ${message.getOrElse("")}")
log.debug(s" REASON: ${reason.getMessage}")
super.preRestart(reason, message)
}
override def postRestart(reason: Throwable) {
log.debug("restart completed!")
log.debug("ArtGroupDeleteESActor: postRestart")
log.debug(s" REASON: ${reason.getMessage}")
super.postRestart(reason)
}
def receive = {
case ArtGroupDeleteFromES(uuidList) =>
throw new Exception("Booom")
sender ! true
}
case message =>
log.warn("Received unknown message: {}", message)
unhandled(message)
}
}
and here is the how i am sending this actor a message
class ArtGroupDeletionActor extends Actor{
val log = LoggerFactory.getLogger(this.getClass)
override val supervisorStrategy = OneForOneStrategy(
maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
case _:Exception => Restart
}
val artGroupDeleteESActor=context.actorOf(Props[ArtGroupDeleteESActor]
.withDispatcher("akka.actor.ArtGroupDeleteESActor-dispatcher")
,name = "ArtGroupDeleteESActor")
def receive = {
case DeleteArtGroup(uuidList) =>
val future1 = ask(artGroupDeleteESActor, ArtGroupDeleteFromES(uuidList)).mapTo[Boolean]
var isDeletedfromES = Await.result(future1, timeout.duration)
case message =>
log.warn("Unhandled message received : {}", message)
unhandled(message)
}
}
object test extends App{
val artGroupDeletionActor=system.actorOf(Props[ArtGroupDeletionActor]
.withDispatcher("akka.actor.ArtGroupDeletionActor-dispatcher")
,name = "ArtGroupDeletionActor")
artGroupDeletionActor ! DeleteArtGroup(List("123"))
}
the PostRestart() and preRestart() methods are not invoking,but preStart() and postStop() gets called, please guide me where i am doing wrong
(for simplicity I'll call your actors Parent and Child from now on)
What happens here is that when an exception occurs inside Child.receive, it doesn't send a response to Parent, instead, the actor system sends some control instruction for the supervision strategy. However, Parent is blocked on Await waiting for completion of future1, which only happens after the timeout exceeds, and then, in turn, a TimeoutException is thrown inside Parent.receive, killing (restarting) the Parent actor itself, and thus the supervising message of an exception in Child is then passed to deadLetters, never restarting the Child.
You should never, ever, ever block inside an actor, so this is incorrect:
val future1 = ask(artGroupDeleteESActor, ArtGroupDeleteFromES(uuidList)).mapTo[Boolean]
var isDeletedfromES = Await.result(future1, timeout.duration)
Instead, you have to either utilize some kind of message identification to distinguish one reply from another in concurrent environment, or add an onComplete to the Future and send a message to self in the closure (beware: no logic other than sending a message should be executed inside the closure to the Future!).
So, option A:
case class ArtGroupDeleteFromES(id: Long, uuidList: List[String])
case class ArtGroupDeleteFromESResult(id: Long, success: Boolean)
class Parent extends Actor {
override val supervisionStrategy = ...
var msgId = 0L
var pendingRequesters = Map.empty[Long, ActorRef]
val child = context.actorOf(Props[Child])
def nextId = {
msgId += 1
msgId
}
def receive = {
case DeleteArtGroup(uuidList) =>
val id = nextId
pendingRequesters += id -> sender() // store a reference to the sender so that you can send it a message when everything completes
child ! DeleteArtGroupFromES(nextId, uuidList)
case ArtGroupDeleteFromESResult(id, success) =>
// process result...
pendingRequesters(id) ! "done"
pendingRequesters -= id
}
}
And option B:
case class ArtGroupDeleteFromES(uuidList: List[String])
case class ArtGroupDeleteFromESResult(replyTo: ActorRef, success: Boolean)
class Parent extends Actor {
override val supervisionStrategy = ...
val child = context.actorOf(Props[Child])
def receive = {
case DeleteArtGroup(uuidList) =>
val requester = sender() // when the future completes, sender may have already changed, so you need to remember it
(child ? DeleteArtGroupFromES(uuidList)).onComplete {
case Success(success) => self ! ArtGroupDeleteFromESResult(requester, success)
case Failure(e) =>
log.warn("Could not delete...", e)
self ! ArtGroupDeleteFromESResult(requester, success = false)
}
}

how to perform supervision in akka

I have two actors one is parent and one is child ,The child actor is responsible for fetching data from MongoDB against an given id and reply back the data to the calling actor which is a parent in my case ,Now i want to apply supervision in my child actor i know how to perform supervision strategy but how to do it in my code that's confusing me
i am catching exception in my try/catch block so that every type of exception will be caught but then i am stuck on the point how to app,y supervision as i don't know exactly what exception my code will throw in future here is my code please help me
ReadOnlyAdminQueryActor.scala(Patent Actor)
class ReadOnlyAdminQueryActor extends Actor{
val log = LoggerFactory.getLogger("controller")
case ReadOnlyAdminReadByID(idList)=>
var RetunedLists = new MutableList[ReadOnlyAdmin]()
RetunedLists= readById(idList)
sender ! RetunedLists //return list of ReadOnlyAdmin objects to the calling actor (matched uuid results)
def readById(idList:MutableList[Int]):MutableList[ReadOnlyAdmin]= {
var connection=MongoFactory.getConnection
var collection=MongoFactory.getCollection(connection, "readOnlyAdmin")
var RetunedList = new MutableList[ReadOnlyAdmin]()
var id:Int=0
var email:String=""
var SecondryEmail:Option[String]=None
var FirstName:String=""
var LastName:String=""
var userStatus:String=""
log.info("readOnlyAdmin query class data method readByID")
for(Id<-idList){
val q=QueryBuilder.start("_id").is(Id)
val cursor=collection.find(q.get)
var obj=new BasicDBObject
try {
while(cursor.hasNext)
{
obj=cursor.next().asInstanceOf[BasicDBObject]
id=obj.getString("_id").toInt
email=obj.getString("Email")
SecondryEmail=Option(obj.getString("SecondryEmail"))
FirstName=obj.getString("FirstName")
LastName=obj.getString("LastName")
userStatus=obj.getString("UserStatus")
val readOnlyAdmin=new ReadOnlyAdmin(id,FirstName, LastName, email, SecondryEmail ,"",UserStatus.withName(userStatus))
RetunedList+=readOnlyAdmin //adding objects in a list
}//end of while
}//end of try
catch
{
case e: Exception => log.error("printStackTrace"+e.printStackTrace)
}
finally{
cursor.close()
MongoFactory.closeConnection(connection)
}
}//end for loop
RetunedList
}
}
ReadOnlyAdminReadMongoActor.scala (Child Actor)
class ReadOnlyAdminReadMongoActor extends Actor{
val log = LoggerFactory.getLogger("controller")
val ReadOnlyAdminQueryActor=context.actorOf(Props[ReadOnlyAdminQueryActor].withDispatcher("akka.actor.readOnlyAdminReadMongoActor-dispatcher"), name = "ReadOnlyAdminQueryActor")
case ReadOnlyAdminReadFromMongoById(readOnlyAdmin,idList)=>
var RetunedLists = new MutableList[ReadOnlyAdmin]()
implicit val timeout = Timeout(10 seconds)//wait for 10 seconds
override val supervisorStrategy: SupervisorStrategy = {
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
case x: Exception => ???
}
}
val future:Future[MutableList[ReadOnlyAdmin]] = ask(ReadOnlyAdminQueryActor,ReadOnlyAdminReadByID(idList)).mapTo[MutableList[ReadOnlyAdmin]]
future.onComplete {
case Success(result)=>
RetunedLists=result
for(a<-RetunedLists)
{
log.info ("id is "+a.getUuid+"First name is "+a.getFirstName
+"Last name is "+a.getLastName+"Email is "+a.getEmail
+"secondry email is "+a.getSecondryEmail+"user status is "+a.getUserStatus)
}
case Failure(e)=>
log.error(" in failure")
log.error("printStackTrace"+e.printStackTrace)
}
object Test extends App{
val system = ActorSystem("TestSystem")
val readOnlyAdmin= new ReadOnlyAdmin
var uuidsList = new MutableList[Int]()
uuidsList+=123
val ReadOnlyAdminReadMongoActor=system.actorOf(Props[ReadOnlyAdminReadMongoActor].withDispatcher("akka.actor.readOnlyAdminReadMongoActor-dispatcher"), name = "ReadOnlyAdminReadMongoActor")
ReadOnlyAdminReadMongoActor ! ReadOnlyAdminReadFromMongoById(readOnlyAdmin,uuidsList)
}
how can i perform supervision in a correct way and how do i came to know which exception will be thrown in my child actor also Fortunately, Java libraries explicitly say what they're going to throw, and Scala libraries almost always throw very little or no even in IDE no information is shown when we hover the mouse on the code
please help me thanks in advance
The supervisor strategy belongs with the Parent, not the Child. The child should throw its exceptions and the parent determines how to handle the failure. In the code below, the Child actor will be restarted 3 times, then terminate:
class Parent extends Actor {
override def preStart(): Unit = {
self ! "Start Child"
}
def receive = {
case "Start Child" => context.actorOf(Props[Child])
}
override def supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 3) {
case ex: Throwable => Restart
}
}
class Child extends Actor {
override def preStart() = {
self ! "Throw"
}
def receive = {
case "Throw" => throw new Exception("Throwing")
}
}

on demand actor get or else create

I can create actors with actorOf and look them with actorFor. I now want to get an actor by some id:String and if it doesnt exist, I want it to be created. Something like this:
def getRCActor(id: String):ActorRef = {
Logger.info("getting actor %s".format(id))
var a = system.actorFor(id)
if(a.isTerminated){
Logger.info("actor is terminated, creating new one")
return system.actorOf(Props[RC], id:String)
}else{
return a
}
}
But this doesn't work as isTerminated is always true and I get actor name 1 is not unique! exception for the second call. I guess I am using the wrong pattern here. Can someone help how to achieve this? I need
Create actors on demand
Lookup actors by id and if not present create them
Ability to destroy on, as I don't know if I will need it again
Should I use a Dispatcher or Router for this?
Solution
As proposed I use a concrete Supervisor that holds the available actors in a map. It can be asked to provide one of his children.
class RCSupervisor extends Actor {
implicit val timeout = Timeout(1 second)
var as = Map.empty[String, ActorRef]
def getRCActor(id: String) = as get id getOrElse {
val c = context actorOf Props[RC]
as += id -> c
context watch c
Logger.info("created actor")
c
}
def receive = {
case Find(id) => {
sender ! getRCActor(id)
}
case Terminated(ref) => {
Logger.info("actor terminated")
as = as filterNot { case (_, v) => v == ref }
}
}
}
His companion object
object RCSupervisor {
// this is specific to Playframework (Play's default actor system)
var supervisor = Akka.system.actorOf(Props[RCSupervisor])
implicit val timeout = Timeout(1 second)
def findA(id: String): ActorRef = {
val f = (supervisor ? Find(id))
Await.result(f, timeout.duration).asInstanceOf[ActorRef]
}
...
}
I've not been using akka for that long, but the creator of the actors is by default their supervisor. Hence the parent can listen for their termination;
var as = Map.empty[String, ActorRef]
def getRCActor(id: String) = as get id getOrElse {
val c = context actorOf Props[RC]
as += id -> c
context watch c
c
}
But obviously you need to watch for their Termination;
def receive = {
case Terminated(ref) => as = as filterNot { case (_, v) => v == ref }
Is that a solution? I must say I didn't completely understand what you meant by "terminated is always true => actor name 1 is not unique!"
Actors can only be created by their parent, and from your description I assume that you are trying to have the system create a non-toplevel actor, which will always fail. What you should do is to send a message to the parent saying “give me that child here”, then the parent can check whether that currently exists, is in good health, etc., possibly create a new one and then respond with an appropriate result message.
To reiterate this extremely important point: get-or-create can ONLY ever be done by the direct parent.
I based my solution to this problem on oxbow_lakes' code/suggestion, but instead of creating a simple collection of all the children actors I used a (bidirectional) map, which might be beneficial if the number of child actors is significant.
import play.api._
import akka.actor._
import scala.collection.mutable.Map
trait ResponsibleActor[K] extends Actor {
val keyActorRefMap: Map[K, ActorRef] = Map[K, ActorRef]()
val actorRefKeyMap: Map[ActorRef, K] = Map[ActorRef, K]()
def getOrCreateActor(key: K, props: => Props, name: => String): ActorRef = {
keyActorRefMap get key match {
case Some(ar) => ar
case None => {
val newRef: ActorRef = context.actorOf(props, name)
//newRef shouldn't be present in the map already (if the key is different)
actorRefKeyMap get newRef match{
case Some(x) => throw new Exception{}
case None =>
}
keyActorRefMap += Tuple2(key, newRef)
actorRefKeyMap += Tuple2(newRef, key)
newRef
}
}
}
def getOrCreateActorSimple(key: K, props: => Props): ActorRef = getOrCreateActor(key, props, key.toString)
/**
* method analogous to Actor's receive. Any subclasses should implement this method to handle all messages
* except for the Terminate(ref) message passed from children
*/
def responsibleReceive: Receive
def receive: Receive = {
case Terminated(ref) => {
//removing both key and actor ref from both maps
val pr: Option[Tuple2[K, ActorRef]] = for{
key <- actorRefKeyMap.get(ref)
reref <- keyActorRefMap.get(key)
} yield (key, reref)
pr match {
case None => //error
case Some((key, reref)) => {
actorRefKeyMap -= ref
keyActorRefMap -= key
}
}
}
case sth => responsibleReceive(sth)
}
}
To use this functionality you inherit from ResponsibleActor and implement responsibleReceive. Note: this code isn't yet thoroughly tested and might still have some issues. I ommited some error handling to improve readability.
Currently you can use Guice dependency injection with Akka, which is explained at http://www.lightbend.com/activator/template/activator-akka-scala-guice. You have to create an accompanying module for the actor. In its configure method you then need to create a named binding to the actor class and some properties. The properties could come from a configuration where, for example, a router is configured for the actor. You can also put the router configuration in there programmatically. Anywhere you need a reference to the actor you inject it with #Named("actorname"). The configured router will create an actor instance when needed.