1

The data layer in my web application is comprised of Akka actors. Whenever I need to access data, I invoke the ActorSystem mechanism like so:

val myActor = system.actorOf(Props[MyActor], name = "myactor")      
implicit val timeout = Timeout(120 seconds)
val future = myActor ? Request1
val result = Await.result(future, timeout.duration)

I'm using Play, and the ActorSystem variable is obtained through injection:

class MyClass @Inject() (system: ActorSystem)

But I'm getting the following exception saying that the actor name is not unique the second time I access the function, how to fix this? How to name the actor, taking into account that can be used concurrently by more than one thread?

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[InvalidActorNameException: actor name [myactor] is not unique!]]

** EDIT **

What I'm trying to achieve is something similar to having a container of Entity Beans in the EJB model, where each actor would be an Entity Bean. The difference I'm noticing is that the actors are not created/destroyed automatically as needed.

ps0604
  • 1,227
  • 23
  • 133
  • 330
  • So you want a separate `Actor` for each of the entities/documents/rows? In this case I would name them after the row's key. You should create a "parent" actor representing your collection of entities (table of rows), then query this "parent" actor asking for a specific key. If it already has an actor corresponding to this key, return it, if not, create it first. – Paweł Bartkiewicz Nov 23 '16 at 03:17
  • Each actor should be like a DAO class, with create/read/update/delete methods – ps0604 Nov 23 '16 at 03:32
  • OK, this makes sense. I'll update my answer. – Paweł Bartkiewicz Nov 23 '16 at 03:34

2 Answers2

3

Depending on your goal, the question may be not how to name an actor, but when to create it. You are creating a new actor every time you need to access some data. I suppose you aren't stopping old actors when they are no longer needed.

You should probably create an actor once (or multiple times if you want a pool of actors, but using different names) and reuse it later by keeping an ActorRef somewhere or using dependency injected actors. You can also use system.actorFor or system.actorSelection (depending on Akka version you're using) if you really need to.

Most of the time you don't even need an explicit ActorRef because you want to reply to a sender of some message.

If you have to create a separate actor each time, then see Wonpyo's answer. In my opinion, though, you could simply use a Future directly instead.

There is a great guide on Actors in the Akka documentation.

Edit:

Since you specified you want each actor to act like a DAO class, I think it should look something like:

// Somewhere in some singleton object (injected as dependency)
val personDao : ActorRef = system.actorOf(Props[PersonDaoActor], name = "personDao")
val fruitDao  : ActorRef = system.actorOf(Props[FruitDaoActor],  name = "fruitDao")

Then, when you need to access some data:

val johnSmithFuture = personDao ? Get("John Smith")
johnSmithFuture.map {
  case Person(name, age) => println(s"${name} ${age}")
}

Alternatively, instead of personDao you can use system.actorFor("personDao") (or system.actorSelection equivalent in Akka 2.4). You can also inject actors directly.

If you want multiple actors to process your messages in parallel you can use routers. Example:

val personDao: ActorRef =
  system.actorOf(RoundRobinPool(5).props(Props[PersonDaoActor]), "personDao")

It would create 5 instances of your PersonDaoActor and distribute any messages sent to personDao among those 5 actors, so you could process 5 queries in parallel. If all 5 actors are busy, messages will be queued.

Using Await defeats the purpose of Akka in this case. There are some cases when this is the only option (legacy code, mostly), but using it every time effectively makes your code completely blocking, maybe even single-threaded (depending on your actor code). This is especially true in Play, which is designed to do everything asynchronously, so there's no need to Await.

It may be a good idea to reconsider if actors are really the best solution to your problem. If all you want is parallel execution, then Futures are much simpler. Some people still use actors in such case because they like the abstraction and the simplicity of routing. I found an interesting article describing this in detail: "Don't use Actors for concurrency" (also read the comments for opposing views).

  • I don't have to create a separate actor each time, please see my edit – ps0604 Nov 23 '16 at 03:05
  • If I declare the actors in some singleton object, what happens if two classes access the same actor declaration? Would they access two different actors in parallel? – ps0604 Nov 23 '16 at 04:30
  • In general, no, an `ActorRef` points to a single actor instance, so requests to the actor would be queued. There are some exceptions, see [dispatchers](http://doc.akka.io/docs/akka/snapshot/scala/dispatchers.html). You can use [routers](http://doc.akka.io/docs/akka/snapshot/scala/routing.html) if you want to create a pool of actors. Depending on your router, they could process messages in a round-robin fashion, for example. I think the easiest way to think about actors at the beginning is treating them like message queues with some internal state. One actor = one queue. – Paweł Bartkiewicz Nov 23 '16 at 12:25
  • @ps0604 Please look at my updated answer, I hope it's clearer now. – Paweł Bartkiewicz Nov 23 '16 at 13:28
  • Thanks for the good answer. It seems that using `routes` will distribute/balance the messages, something I won't get using `Futures`. Also, using `routes` I can specify beforehand the number of actors to create. – ps0604 Nov 23 '16 at 15:14
  • Actually, you can [create your own thread pool](http://stackoverflow.com/questions/15285284/how-to-configure-a-fine-tuned-thread-pool-for-futures), setting the number of threads yourself. Then you simply create `Future`s and they are distributed among those threads. The only difference is that you would pass the data directly to the `Future` instead of using the abstraction of message passing. Both solutions are fine if you use them correctly. – Paweł Bartkiewicz Nov 23 '16 at 15:23
1

Actor System requires unique name (path) for each actor.

Path has follwing format akka://system@host:port/user/{your-actor-path}

For example

   val system = ActorSystem("hello")
   val myActor = system.actorOf(Props[MyActor], name ="myactor")
   //  myActor Path 
   // "akka://hello/user/myactor"  // purely local
   // "akka.tcp://hello@ip:port/user/myactor" // remote

and in your code, myActor is created everytime, you make a call.

which makes an actor in the same path everytime.

Thus, Bad solution is to change the code as following

 val myActor = system.actorOf(Props[MyActor])      

If you don't assign a name to an actor then actor system will assign an random name

and myActor will not have same path for each function call.

But, this is really bad solution, since myActor will not be destructed

(Actor is not terminated by GC)

If you keep calling the function, then your memory will be out of space one day.

So, please DESTRUCT myActor after you done with the function.

Community
  • 1
  • 1
Wonpyo Park
  • 301
  • 3
  • 11