I'm building a simple logging class in scala which would write all log information to a file. This is part of a homework assignment. Hence I cannot use the already available loggers in java or scala or akka libraries. Can any of you please tell how to uniquely identify actors in scala i.e., is there a resource ID or any other ID for each actor. If so, how can it be accessed?
I tried using hashCode() on the actor objects. But it does not give the expected result, as the value changes for each object and many objects can be created for a single actor.
If you are using akka actors you can get the name of the actor by looking at self.path (self is an ActorRef)
http://doc.akka.io/api/akka/2.0.4/#akka.actor.ActorPath
EDIT:
If you are using scala actors then you could do something like...
class MyActor(name: String) extends Actor {
def act() {
receive {
case _ => println("Message on actor: " + name)
}
}
}
val actor1 = new MyActor("actor1")
val actor2 = new MyActor("actor2")
Related
I'm developing an application using Akka, and a thing that kind of bugs me the whole time regards message declaration with the Actor's. Where should I declare the messages? In the receivers companion object or the senders companion object or on some third place?
The Akka team recommends Message should be defined in the same place the props method should be: in the Receiver's Companion object because the Receiver implements the receive partial function and needs to know about all the messages it supports. Also, multiple senders can send a set of messages (implemented by the Receiver), so you cannot put it in one single sender.
If the official Typesafe Activator template activator-akka-scala-seed is of any importance regarding Akka's good practices the messages should be part of companion object as shown in the following PingActor actor (copied directly from the template):
package com.example
import akka.actor.{Actor, ActorLogging, Props}
class PingActor extends Actor with ActorLogging {
import PingActor._
var counter = 0
val pongActor = context.actorOf(PongActor.props, "pongActor")
def receive = {
case Initialize =>
log.info("In PingActor - starting ping-pong")
pongActor ! PingMessage("ping")
case PongActor.PongMessage(text) =>
log.info("In PingActor - received message: {}", text)
counter += 1
if (counter == 3) context.system.shutdown()
else sender() ! PingMessage("ping")
}
}
object PingActor {
val props = Props[PingActor]
case object Initialize
case class PingMessage(text: String)
}
Note PingActor that holds all the accepted messages by the actor (as you may've noticed it's not followed strictly since PongActor.PongMessage is also accepted, but not defined in the companion object PingActor).
From another question How to restrict actor messages to specific types? the Viktor said:
The common practice is to declare what messages an Actor can receive
in the companion object of the Actor, which makes it very much easier
to know what it can receive.
I am trying to use a broadcast router in Scala, if I'm not mistaken it should look like this:
val system = ActorSystem("My beautiful system")
val workerRouter = system.actorOf(Props[Agent].withRouter(BroadcastRouter(individualDefinitions.size)), name = "agentRouter")
That is what I understand from the tutorial I am following.
The workerRouter acts as another actor and I can send messages to this router that will send them to all the Agents (as many as individualDefinitions I have).
The problem is that I'd like to use the individual definitions to build the agents, they actually take some parameters in the constructor and those parameters are in the individualDefinitions.
Q: How could I tell the router to pass those parameters to each one of them as part of the constructor?
Please note each actor should get one individualDefinition and they are all different. I cannot use the solution in a related question where the constructor receives constants: In Akka Java actor model, can a router create actors with non-default constructor?
Please note that here each actor should have different parameters, if one of them is restarted it should get the same parameters it got in the first place. I don't know if that solution could be modified to do that.
A possible solution could be using an actor as the router, to separate creation (constructor) and routing, as in question Akka (java), non blocking broadcast to all children.
I'm not sure that is the "right" approach in this case. Using an actor as the router has several problems (besides of elegance). I am concerned about the actor that works as a router being restarted and losing all its subscribers. If the actor is restarted in half of a loop some actors could also miss some messages if I'm not mistaken.
Thank you.
You can create routers by specifying as routees some already created actors, constructed by whatever logic.
The following example will create 2 actors created differently and then create a round robin router which will route the messages to them.
class MyActor(param1: String) extends Actor with ActorLogging {
def receive: Actor.Receive = {
case msg => log.info("Message from {}: {}", param1, msg)
}
}
object MyActor {
def apply(param: String): Props = Props(new MyActor(param))
}
object Main extends App {
val system = ActorSystem()
val a1 = system.actorOf(MyActor("actor1"))
val a2 = system.actorOf(MyActor("actor2"))
val routerProps = Props.empty.withRouter(RoundRobinRouter(routees = Vector(a1, a2)))
val router = system.actorOf(routerProps)
for (i <- 1 to 10) {
router ! i
}
readLine()
system.shutdown()
}
More details here: http://doc.akka.io/docs/akka/2.2.0/scala/routing.html
public class Master extends UntypedActor {
-----
-----
public Master() {
workerRouter = this.getContext().actorOf(Worker.createWorker().withRouter(new RoundRobinRouter(8)), "workerRouter");
}
With Akka 2.4.2, we can simply use:
workerRouter = this.getContext().actorOf(new RoundRobinPool(noOfWorkers).props(Props.create(Worker.class)), "workerRouter");
This is best Effort code executed in min. time in akka .
So I'm getting started using Akka actors inside of my Play 2.0 app. I noticed quickly that repeated calls to sending messages to the same actor, specified via:
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Resulted in InvalidActorNameException.
I then started reading up on the creation of Actors in this doc
The doc seemed to recommend creating a "master" Actor class with all of the individual actors specified in there. The receive of this actor class would, in turn, match on the message and delegate the message to the appropriate Actor.
So I tried this and now have something like:
class MasterActor extends Actor{
import context._
val emailActor = actorOf(Props[EmailActor], name = "emailActor")
protected def receive = {
case reminder : BirthdayReminder => emailActor ! reminder
}
}
Problem is that I'm in the same situation I was before. I don't know how to avoid the InvalidActorNameException when I try something like:
val myActor = Akka.system.actorOf(Props[MasterActor], name = "MasterActor")
myActor ! BirthdayReminder(someBirthday)
So what's the right way to organize my Actors?
If you want only one MasterActor, why are you creating multiple ones? You should just look up the one you have already created:
val actorRef = context.actorFor("MasterActor")
actorRef ! BirthdayReminder(someBirthday)
I'm new to scala and I'm trying to write a program in scala which creates multiple (say, 30) actors and passes messages between them.
Below is what i have managed till now:
import scala.actors.Actor
import scala.util.Random
class MyActor(val id:Int, val N:Int) extends Actor {
def act() {
println ("Starting actor: " + id)
/**
react{
case str : String =>
println("Received Msg: " + str)
val randNo : Int = Random.nextInt(N)
println("Actor " + id + " Picking a random actor: " + randNo)
// Here, I should forward the message received to the ALREADY created and started actors
// val objActor = new MyActor(randNo : Int, N : Int)
// objActor.start
// objActor ! str
}
*/
}
}
object Main {
def main(args:Array[String]) {
if(args.length == 0)
{
println("Usage scala Main <numNodes>")
sys.exit()
}
val N : Int = (args(0)).toInt
// Starting all actors
for (i: Int <- 0 to N-1) {
val a = new MyActor(i : Int, N : Int)
println ("About to start actor " + a.id)
a.start
// a!"Broadcast this msg to all actors"
}
}
}
The objective of the program is to create multiple actors and forward a string from one actor to another.
The above code creates 'N' number of actors given as command line argument.
These actors are created and started by the object Main.
Main should send a message to ONLY ONE of the above created actors.
The actor which receives the message from the Main should forward the same message to another ALREADY created/started actor.
Is this possible? If so, can you please guide me on the right direction?
Thanks in advance,
MS
First off, I would suggest checking out Akka actors, soon to replace Scala actors in Scala 2.10 which is hopefully coming out in the next few months.
That being said, it definitely is possible, the workflow would go something like this (in Akka at least):
Create an ActorSystem in your main method.
Spawn Actor as desired within the ActorSystem via the actorOf method, which will return an ActorRef object.
Pick one of these ActorRef's to send the message to.
In the Actor implementation, somehow make the Actor aware of the others (perhaps via the constructor), and figure out how you want the propagate the String throughout the system (on this note, I generally prefer using Scala case classes as messages).
This sort of sounds like a state machine like system - one idea off the top of my head that I've been playing with is to treat the ActorSystem as a graph entity, meaning for each Actor instance you pass it a list of it's neighbors (perhaps as a Vector[ActorRef]).
You can also check out the new Actors DSL the Akka team recently introduced.
For learning more about Akka, I recommend the resources:
Jonas Bonér's recent talk at NY Scala introducing Akka
Akka in Action (MEAP)
I found a way to do the above stated problem in scala itself by using an array of actors.
since all the actors are going to perform the same operation (i.e.,) forwarding the message, it is enough to create multiple instances of MyActor.
Thanks a lot!
I am writing a program using Actors in scala in which an actor (Actor1) accepts two numbers as command line arguments and sends a message to another actor Actor2 (which calculates their sum). Actor2 sends the result to Actor1, who prints it on the screen.
class Actor1 extends Actor {
def main(args: Array[String]) {
val n= Integer.parseInt(args(0))
val k= Integer.parseInt(args(1))
val actor2 = new Actor2
actor2 ! (n, k)
}
def act()
{
react{
case num: Integer =>
println(num)
case _=>
println("Sum not received")
exit
}
}
}
class Actor2 extends Actor {
def act(){
loop
{
react
{
case(n:Int, k:Int) =>
val i = n + k
val actor1 = new Actor1
actor1 ! i}
}
}
}
Is it possible to define main() inside the class that extends Actor, and is there any other way to accept command line arguments by the Actor?
It shows the error: class Actor1 needs to be abstract, since method act in trait Reactor of type ()Unit is not defined.
First things first: You should consider using akka instead of the default Scala actors. It's just better.. in pretty much every aspect.
That aside, here are a few answers for your:
Your main method should be in a standalone object (not a companion object). So use something like this: object Main { def main(args:Array[String]) { ... } } and start your program via the Main object/class. (This is due to the definition inside the Actor1 class being non-static and the problem that if you define a companion object the .class filenames collide.)
In your code, something seems to have gone wrong with the brackets - or did you place Actor2 inside the Actor1 class on purpose? It's cleaner, if you just make three separate classes/objects: Actor1, Actor2, Main.
When you create Scala actors, you have to explicitly start them (not so with akka 2.x). So you miss your calls to actor1.start and such. Note that your program will then not terminate before your actors have terminated, so don't wonder if it doesn't stop anymore after you add that.
Finally, some minor hints:
You may want to consider using !? and send back your answer to the original caller, as this also allows you to have a proper termination condition.
Integer.parseInt("0") can be written more simply as "0".toInt