I'm trying to make a small Akka example work using the following code:
class Sender extends Actor {
#volatile var numEchoes = 0
def receive = {
case Echo => {
numEchoes += 1
println(numEchoes)
if(numEchoes < Main.NUMBER_OF_ECHOES) {
println("Heard an echo...")
}
else {
// all echoes have been received.
println("All echoes heard.")
context.system.terminate
}
}
}
}
This actor is going to receive Echo messages from several Receiver actors:
class Receiver extends Actor {
def receive = {
case Echo => sender ! Echo
}
}
However, numEchoes always prints out 1. If I was doing something wrong, I'd expect 0, but this value makes me believe something else is at play here, but I'm unable to figure out what it is.
The rest of the code is just sending this specific actor a certain number of messages (lets assume 10). I see Heard an echo... printed out 10 times, but the value of this variable does not change.
#wheaties was correct. The error was in the Main object, due to some late and careless copy pasting... When I was creating 1 Sender and 10 Receiver actors, this is the code I was using:
// Create the actor that will send out the messages
val sender = actorSystem.actorOf(Props[Sender], "sender")
var actorList = List[ActorRef]()
for(i <- 1 to NUMBER_OF_ECHOES) {
val receiver = actorSystem.actorOf(Props[Sender], "receiver"+i)
actorList ::= receiver
}
Of course, creating the receivers as Senders is completely wrong, so all I had to do was fix the typo and correctly spawn the actors:
// Create the actor that will send out the messages
val sender = actorSystem.actorOf(Props[Sender], "sender")
var actorList = List[ActorRef]()
for(i <- 1 to NUMBER_OF_ECHOES) {
val receiver = actorSystem.actorOf(Props[Receiver], "receiver"+i)
actorList ::= receiver
}
Related
Consider that i have four actors(1,2,3,4) in a same actor system.Each actor can send message only with its neighbors who has not sent a message to it(i.e. 1 can send only to 2 and 4. Also 2 and 4 can only send to 3 because their neighbor 1 has already sent a message). when an actor receives message from both its neighbors, it prints its name and the system stops.I am able to partially implement.But issue here is in the same time two actors gets message from both their neighbors and stops.For example, if i start the process at 1, 1 sends message to 4 and 2,2 to 3 and 4 to 3 so theoretically 3 should get printed but i get 2 and 3 both printed.Please suggest what can be done.Below is my sample logic.
object Main extends App {
//creating a actor system
val actorSystem = ActorSystem("System")
//creating four actor instances with id as 1,2,3,4
for (i <- 1 to 4) {
actorSystem.actorOf(CircularActor.props(4), "" + i)
}
//initiating message to actor 1
actorSystem.actorSelection(s"/user/1") ! "hello from x"
}
class CircularActor(n: Int) extends Actor {
//variable to keep a track whether the actor received two meesages(i.e.from both neighbours)
var noOfMessagesReceived = 0
//generic method to send message using actorPath
def messageNeighbour(path:String){
context.actorSelection(path) ! "hello from x"
}
override def receive: Receive = {
case "hello from x" =>
noOfMessagesReceived += 1
if (noOfMessagesReceived == 2) {
println(s"The actor that received both messages is ${self.path.name}")
context.system.terminate()
}
else {
//Figures out id of sender
val pathValue = sender().path.name
//Gets its own name
val ownId = self.path.name.toInt
//Finds out the previous neighbor
val prev = if (ownId - 1 == 0) n else ownId - 1
//Finds next neighbour
val next = if (ownId == n) 1 else ownId + 1
//If the message is from deadletter, then this is the initiator actor
if (pathValue == "deadLetters") {
messageNeighbour(s"/user/$prev")
messageNeighbour(s"/user/$next")
}
//If the message is from its next neighbour,send it to previous
else if (pathValue.toInt == next) {
//introducing random delay
Thread.sleep(1 + Random.nextInt(100))
messageNeighbour(s"/user/$prev")
}
//If none of above,then send it to previous.
else {
Thread.sleep(1 + Random.nextInt(100))
messageNeighbour(s"/user/$next")
}
}
}
object CircularActor {
def props(n: Int): Props = Props(new CircularActor(n))
}
The problem seems to be that you assume that messages are processed in the order in which they are sent, which is not necessarily the case. Message passing is asynchronous, and the only guarantee is that messages are processed in the order that they arrive for any given actor. The order in which messages are processed by different actors is not defined.
So in your system the messages could be processed in this order
<dead> -> 1
1 -> 2,4
4 -> 3
3 -> 2
2 -> 3
2 -> <terminate>
As you can see, actor 2 processes two messages before any other actor.
It is not clear what can be done because it is not clear what you are trying to achieve. But it is dangerous to build actor systems with loops like this. In general, an actor system should be organised as a tree or DAG of requests, with replies sent to the requesting actor.
To achieve required behavior we need an actor for tracking the actors to which messages are received.
Model:
abstract class Direction
object Left extends Direction
object Right extends Direction
object StartPoint extends Direction
object Process
BookKeeper Actor
class BookKeeperActor extends Actor {
var visitedActorRefs: mutable.HashSet[String] = mutable.HashSet.empty[String]
override def receive: Receive = {
case Process =>
if (visitedActorRefs.contains(sender().path.toString)) {
context.stop(self)
context.system.terminate()
println(s"The actor that received both messages is ${sender().path.toString}")
}
else
visitedActorRefs.add(sender().path.toString)
}
}
Circular Actor:
class CircularActor(n: Int, bookKeeper: ActorRef) extends Actor {
//generic method to send message using actorPath
def messageNeighbour(path: String, direction: Direction) {
context.actorSelection(path) ! ("hello from x", direction)
}
override def receive: Receive = {
case ("hello from x", direction: Direction) =>
bookKeeper ! Process
//Figures out id of sender
val pathValue = sender().path.name
//Gets its own name
val ownId = self.path.name.toInt
//Finds out the previous neighbor
val prev = if (ownId - 1 == 0) n else ownId - 1
//Finds next neighbour
val next = if (ownId == n) 1 else ownId + 1
Thread.sleep(1 + Random.nextInt(100))
direction match {
case StartPoint =>
messageNeighbour(s"/user/$prev", Left)
messageNeighbour(s"/user/$next", Right)
case Left => messageNeighbour(s"/user/$prev", Left)
case Right => messageNeighbour(s"/user/$next", Right)
}
}
}
object CircularActor {
def props(n: Int, bookeeper: ActorRef): Props = Props(new CircularActor(n, bookeeper))
}
Main App-
object Main extends App {
val actorSystem = ActorSystem("System")
//creating four actor instances with id as 1,2,3,4
val bookKeeperActor = actorSystem.actorOf(Props(new BookKeeperActor))
for (i <- 1 to 4) {
val ac = actorSystem.actorOf(CircularActor.props(4, bookKeeperActor), "" + i)
}
//initiating message to actor 1
actorSystem.actorSelection(s"/user/1") ! ("hello from x", StartPoint)
}
I know one of the advantages of the actor model is that by handling only one message at a time, concurrency issues are simplified. But it seems to me that my actor is handling multiple messages. In pseudo code I have
var status = 0
def receive = {
case DoSomething =>
val dest = sender()
status = 0
for {
otherActor <- resolveOtherActor("/user/OtherActor")
} yield {
for {
res <- {status = 1
otherActor ? doSomething1
}
res <- {status = 2
otherActor ? doSomething2
}
} yield {
dest ! status
}
}
case GetStatus => sender() ! status
}
If I send a DoSomething messages to this actor, and then immediately send GetStatus to this actor repeatedly, I will see status 0, 1 and 2 coming back in sequence. If the actor model only handled one message at a time, I would only ever see status 2 being returned, since I wouldn't have access to the intermediate status.
It seems that locks are still necessary with the actor pattern. What am I missing?
All bets are off when you close over an actor's mutable state and expose it to other threads, which is what your code is doing when it mutates status inside a (nested) Future. The Akka documentation clearly warns against this.
An actor does process one message at a time:
var status = 0
def receive = {
case IncrementStatus =>
status += 1
case GetStatus =>
val s = status
sender ! s
}
Sending an IncrementStatus, another IncrementStatus, then a GetStatus message from the same sender to the above actor will cause that sender to receive a 2.
However, trying to do the same thing with Futures does not guarantee the same outcome, because a Future is completed asynchronously. For example:
object NumService {
// calculates arg + 1 in the future
def addOne(arg: Int): Future[Int] = {
Future { arg + 1 }
}
}
class MyActor extends Actor {
var status = 0
def receive = {
case IncrementStatusInFuture =>
val s = status
NumService.addOne(s)
.map(UpdateStatus(_))
.pipeTo(self)
case UpdateStatus(num) =>
status = num
case GetStatus =>
val s = status
sender ! s
}
}
We map the Future to create a Future[UpdateStatus], then pipe to the actor itself the result of that Future.
If we send an IncrementStatusInFuture, another IncrementStatusInFuture, then a GetStatus message to MyActor from the same sender, we cannot guarantee that the sender will receive a 2. The actor processes those three messages in order, but one or both of the calls to NumService.addOne might not have completed by the time the actor processes the GetStatus message. This nondeterministic behavior is a characteristic of a Future; it is not a violation of the actor principle of one-message-at-a-time processing.
I'm trying to keep counting on each successful import. But here is a problem - Counter works if the router receives a message from its parent but if I'm trying to send a message from its children it receives it but doesn't update the global variable that is out of the scope.
I know it sounds complicated. Let me show you the code.
Here is the router
class Watcher(size: Int) extends Actor {
var router = {
val routees = Vector.fill(size) {
val w = context.actorOf(
Props[Worker]
)
context.watch(w)
ActorRefRoutee(w)
}
Router(RoundRobinRoutingLogic(), routees)
}
var sent = 0
override def supervisorStrategy(): SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 100) {
case _: DocumentNotFoundException => {
Resume
}
case _: Exception => Escalate
}
override def receive: Receive = {
case container: MessageContainer =>
router.route(container, sender)
case Success =>
sent += 1
case GetValue =>
sender ! sent
case Terminated(a) =>
router.removeRoutee(a)
val w = context.actorOf(Props[Worker])
context.watch(w)
router = router.addRoutee(w)
case undef =>
println(s"${this.getClass} received undefinable message: $undef")
}
}
Here is the worker
class Worker() extends Actor with ActorLogging {
var messages = Seq[MessageContainer]()
var received = 0
override def receive: Receive = {
case container: MessageContainer =>
try {
importMessage(container.message, container.repo)
context.parent ! Success
} catch {
case e: Exception =>
throw e
}
case e: Error =>
log.info(s"Error occurred $e")
sender ! e
case undef => println(s"${this.getClass} received undefinable message: $undef")
}
}
So on supervisor ? GetValue I get 0 but suppose to have 1000.The strangest thing is that when I debug it with the breakpoint right on the case Success => ... the value is incremented every time the new message arrives. But supervisor ? GetValue still returns 0.
Let's assume I want to count on case container: MessageContainer => ... and it will magically work; I'll get desirable number, but it doesn't show if I actually imported anything. What's going on?
Here is the test case.
#Test
def testRouter(): Unit = {
val system = ActorSystem("RouterTestSystem")
// val serv = AddressFromURIString("akka.tcp://master#host:1334")
val supervisor = system.actorOf(Props(new Watcher(20)))//.withDeploy(akka.actor.Deploy(scope = RemoteScope(serv))))
val repo = coreSession.getRepositoryName
val containers = (0 until num)
.map(_ => MessageContainer(MessageFactory.generate("/"), repo))
val watch = Stopwatch.createStarted()
(0 until num).par
.foreach( i => {
supervisor ! containers.apply(i)
})
implicit val timeout = Timeout(60 seconds)
val future = supervisor ? GetValue
val result = Await.result(future, timeout.duration).asInstanceOf[Int]
val speed = result / (watch.elapsed(TimeUnit.MILLISECONDS) / 1000.0)
println(f"Import speed: $speed%.2f")
assertEquals(num, result)
}
Can you please explained it in details. Why is it happening? Why only on message received from the children? Another approach?
Well... there can be many potential problems hidden in the parts of code that you have not shared. But, for the sake of this discussion I will assume that everything else is fine and we will just discuss problems with your shared code.
Now, let me explain a bit about Actors. To put things simply, every actor has a mailbox (where it keeps messages in the sequence they were received) and processes them one by one in the order they were received. Since the mailbox is used like a Queue we will refer to it as a Queue in this discussion.
Also... I don't know what this container.apply(i) is going to return... so I will refer to the return value of that container.apply(1) as MessageContainer__1
In your test runner you are first creating an instance of Watcher,
val supervisor = system.actorOf(Props(new Watcher(20)))
Now, lets say that you are sending these 2 messages (num = 2) to supervisor,
So supervisor's mailbox will look something like,
Queue(MessageContainer__0, MessageContainer__1)
Then you send it another message GetValue so the mailbox will look like,
Queue(MessageContainer__0, MessageContainer__1, GetValue)
Now the actor will process the first message and pass it to the workers, the mail-box will look like,
Queue(MessageContainer__1, GetValue)
Now even if your worker is ultra-fast and instantaneous in sending the reply the mailbox will look like,
Queue(MessageContainer__1, GetValue, Success)
And now since your worker super-ultra-fast and instantaneously replies with a Success, the state after passing the second MessageContainer will look like,
Queue(GetValue, Success, Success)
And... here is the root of your problem. The Supervisor sees the GetValue massage before any Success messages, no matter how fast your workers are.
And thus it will process GetValue and reply with current value of sent which is 0.
I am trying to continuously read the wikipedia IRC channel using this lib: https://github.com/implydata/wikiticker
I created a custom Akka Publisher, which will be used in my system as a Source.
Here are some of my classes:
class IrcPublisher() extends ActorPublisher[String] {
import scala.collection._
var queue: mutable.Queue[String] = mutable.Queue()
override def receive: Actor.Receive = {
case Publish(s) =>
println(s"->MSG, isActive = $isActive, totalDemand = $totalDemand")
queue.enqueue(s)
publishIfNeeded()
case Request(cnt) =>
println("Request: " + cnt)
publishIfNeeded()
case Cancel =>
println("Cancel")
context.stop(self)
case _ =>
println("Hm...")
}
def publishIfNeeded(): Unit = {
while (queue.nonEmpty && isActive && totalDemand > 0) {
println("onNext")
onNext(queue.dequeue())
}
}
}
object IrcPublisher {
case class Publish(data: String)
}
I am creating all this objects like so:
def createSource(wikipedias: Seq[String]) {
val dataPublisherRef = system.actorOf(Props[IrcPublisher])
val dataPublisher = ActorPublisher[String](dataPublisherRef)
val listener = new MessageListener {
override def process(message: Message) = {
dataPublisherRef ! Publish(Jackson.generate(message.toMap))
}
}
val ticker = new IrcTicker(
"irc.wikimedia.org",
"imply",
wikipedias map (x => s"#$x.wikipedia"),
Seq(listener)
)
ticker.start() // if I comment this...
Thread.currentThread().join() //... and this I get Request(...)
Source.fromPublisher(dataPublisher)
}
So the problem I am facing is this Source object. Although this implementation works well with other sources (for example from local file), the ActorPublisher don't receive Request() messages.
If I comment the two marked lines I can see, that my actor has received the Request(count) message from my flow. Otherwise all messages will be pushed into the queue, but not in my flow (so I can see the MSG messages printed).
I think it's something with multithreading/synchronization here.
I am not familiar enough with wikiticker to solve your problem as given. One question I would have is: why is it necessary to join to the current thread?
However, I think you have overcomplicated the usage of Source. It would be easier for you to work with the stream as a whole rather than create a custom ActorPublisher.
You can use Source.actorRef to materialize a stream into an ActorRef and work with that ActorRef. This allows you to utilize akka code to do the enqueing/dequeing onto the buffer while you can focus on the "business logic".
Say, for example, your entire stream is only to filter lines above a certain length and print them to the console. This could be accomplished with:
def dispatchIRCMessages(actorRef : ActorRef) = {
val ticker =
new IrcTicker("irc.wikimedia.org",
"imply",
wikipedias map (x => s"#$x.wikipedia"),
Seq(new MessageListener {
override def process(message: Message) =
actorRef ! Publish(Jackson.generate(message.toMap))
}))
ticker.start()
Thread.currentThread().join()
}
//these variables control the buffer behavior
val bufferSize = 1024
val overFlowStrategy = akka.stream.OverflowStrategy.dropHead
val minMessageSize = 32
//no need for a custom Publisher/Queue
val streamRef =
Source.actorRef[String](bufferSize, overFlowStrategy)
.via(Flow[String].filter(_.size > minMessageSize))
.to(Sink.foreach[String](println))
.run()
dispatchIRCMessages(streamRef)
The dispatchIRCMessages has the added benefit that it will work with any ActorRef so you aren't required to only work with streams/publishers.
Hopefully this solves your underlying problem...
I think the main problem is Thread.currentThread().join(). This line will 'hang' current thread because this thread is waiting for himself to die. Please read https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join-long- .
I'm very new to Scala and have been fiddling around with an Actor. I've written one that I would have expected would keep sending messages back and forth forever. But when I run it, person1 sends a message that is successfully received by person2, but person1 never gets the message back. (I only get one "Sending" and one "Responding".) I'm sure I'm just misunderstanding something simple.
import scala.actors.Actor
import scala.actors.Actor._
case object Hello
class Person() extends Actor {
def talk(p:Person) {
Console.println("Sending")
p ! Hello
}
def act() {
loop {
react {
case Hello => {
Console.println("Responding")
// This doesn't actually send a message back to the sender.
sender ! Hello
}
}
}
}
}
object pingpong extends Application {
val person1 = new Person
val person2 = new Person
person1.start
person2.start
person1.talk(person2)
}
Any ideas?
EDIT: This works by explicitly passing the sender as part of the message, rather than using the sender method:
class Person() extends Actor {
def talk(p:Person) {
Console.println("Sending")
p ! (Hello, this)
}
def act() {
loop {
react {
case (Hello, theSender:Actor) => {
Console.println("Responding")
theSender ! (Hello, this)
}
}
}
}
}
Is the problem just that I shouldn't be using sender like I was using it, or is there something else going on? Can one use sender to send a message to the sender?