I have the following Actor Model declaration in akka:
val wireA = system.actorOf(Props(new Wire(false)), "Input")
val wireB = system.actorOf(Props(new Wire(false)), "Output")
inverter ! generateOutput(wireA, wireB)
From the generateOutput(input:ActorRef, output:ActorRef),
I need to access the boolean parameter which constructs each particularActorRef (i.e the paramater false which is found in each respective Wire Constructor.
How does it can be reached?
You can send a message to each actor, asking for its current status:
case object Status
case object StatusResult(value: Boolean)
class MyActor(wire: ActorRef) extends Actor {
wire ! Status
def receive = {
case StatusResult(value) => ...
}
wireA and wireB are ActorRefs, they do not expose their state and the only way to communicate with them is via messages.
It's not the way you should play with Actors. You get the ActorRef and you you play with it only with the messages. You can ask the actor of the value of the boolean by passing a message to it:
wireA ! "getVal"
and waiting for the response in the sender actor. Please check the basic tutorial on Actors:
http://alvinalexander.com/scala/scala-akka-actors-ping-pong-simple-example
Related
I'm testing an actor that uses an asnychronous future-based API. The actor uses the pipe pattern to send a message to itself when a future completes:
import akka.pattern.pipe
// ...
// somewhere in the actor's receive method
futureBasedApi.doSomething().pipeTo(self)
In my test I mock the API so I control future completion via promises. However, this is interleaved with other messages sent directly to the actor:
myActor ! Message("A")
promiseFromApiCall.success(Message("B"))
myActor ! Message("C")
Now I'm wondering how I can guarantee that the actor receives and
processes message B between message A and C in my test because message B is actually sent in another thread, so I can't control the order
in which the actor's mailbox receives the messages.
I thought about several possible solutions:
sleep after each message for a few milliseconds to make another
order very unlikely
wait for the actor to acknowledge each message, although
acknowledgement is only required for testing
send message B directly to the actor to simulate completion of the
future and write a separate test that ensures that the pipe pattern
is properly used (the test above would not fail if the actor would
not pipe the result message to itself)
I don't really like either of these options but I tend to use the last
one. Is there another better way I can enforce a certain message order in the tests?
Clarification: The question is not how to deal with the fact that messages might be received in random order in production. Controlling the order in the test is essential to make sure that the actor can actually deal with different message orders.
One idea is to define a flag in your actor that indicates whether the actor has received message B. When the actor receives message C, the actor can stash that message C if the flag is false, then unstash it once the actor receives message B. For example:
class MyActor extends Actor with Stash {
def receiveBlock(seenMsgB: Boolean, seenMsgC: Boolean): Receive = {
case MakeApiCall =>
callExternalApi().mapTo[MessageB].pipeTo(self)
case m: MessageB if seenMsgC => // assume msg C has been stashed
unstashAll()
// ...do something with msg B
become(receiveBlock(true, seenMsgC)) // true, true
case m: MessageB if !seenMsgC =>
// ...do something with message B
become(receiveBlock(true, seenMsgC)) // true, false
case m: MessageC if seenMsgB =>
// ...do something with message C
context.become(receiveBlock(seenMsgB, true)) // true, true
case m: MessageC if !seenMsgB =>
stash()
context.become(receiveBlock(seenMsgB, true)) // false, true
case ...
}
def receive = receiveBlock(false, false)
}
After reading a lot more about akka, I finally found a better solution: Replacing the actor mailbox with one I can observe in the tests. This way I can wait until the actor receives a new message after I complete the promise. Only then the next message is sent. The code for this TestingMailbox is given at the end of the post.
Update: In Akka Typed this can be achieved very elegantly with a BehaviorInterceptor. Just wrap the Behavior under test with a custom interceptor that forwards all messages and signals but lets you observe them.
The mailbox solution for untyped Akka is given below.
The actor can be configured like this:
actorUnderTest = system.actorOf(Props[MyActor]).withMailbox("testing-mailbox"))
I have to make sure the "testing-mailbox" is known by the actor system by providing a configuration:
class MyTest extends TestKit(ActorSystem("some name",
ConfigFactory.parseString("""{
testing-mailbox = {
mailbox-type = "my.package.TestingMailbox"
}
}""")))
with BeforeAndAfterAll // ... and so on
With this being set up, I can change my test like this:
myActor ! Message("A")
val nextMessage = TestingMailbox.nextMessage(actorUnderTest)
promiseFromApiCall.success(Message("B"))
Await.ready(nextMessage, 3.seconds)
myActor ! Message("C")
With a little helper method, I can even write it like this:
myActor ! Message("A")
receiveMessageAfter { promiseFromApiCall.success(Message("B")) }
myActor ! Message("C")
And this is my custom mailbox:
import akka.actor.{ActorRef, ActorSystem}
import akka.dispatch._
import com.typesafe.config.Config
import scala.concurrent.{Future, Promise}
object TestingMailbox {
val promisesByReceiver =
scala.collection.concurrent.TrieMap[ActorRef, Promise[Any]]()
class MessageQueue extends UnboundedMailbox.MessageQueue {
override def enqueue(receiver: ActorRef, handle: Envelope): Unit = {
super.enqueue(receiver, handle)
promisesByReceiver.remove(receiver).foreach(_.success(handle.message))
}
}
def nextMessage(receiver: ActorRef): Future[Any] =
promisesByReceiver.getOrElseUpdate(receiver, Promise[Any]).future
}
class TestingMailbox extends MailboxType
with ProducesMessageQueue[TestingMailbox.MessageQueue] {
import TestingMailbox._
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef],
system: Option[ActorSystem]) =
new MessageQueue()
}
If it is so important to order messages you should use ask (?) which returns Future and chain them even if you dont expect any response from an actor.
In my Scala application say I have Actor A and Actor B. I want to devise a test case in ScalaTest that would allow me to send a message to Actor A and see what message it sends to Actor B in order to see if A is properly processing it's data and sending the right message to B. How would one test this? It took me a long time to get this cooked up on my own...but it does seem to mostly work.
class A extends Actor { ... }
class B extends Actor { ... }
class C(p: TestProbe) extends B {
override def receive = {
LoggingReceive {
case x =>
println(x.toString)
p.ref ! x
}
}
}
case class MsgToB(...)
// Spec class which extends TestKit
"A" should {
"send the right message to B" {
val p = TestProbe()
val a = TestActorRef[A]
val c = TestActorRef(Props(new C(p)))
// Assume A has a reference to C. Not shown here.
a ! msg
// Assert messages
p.expectMsgType[MsgToB]
}
}
Is this the best means of doing this? Is there a better practice?
To me it sounds like what you want is to test the behaviour of actor A in isolation. In order to do this, you need to be able to control how actor A gets its reference to actor B. For example, you could provide the reference in the actor's constructor:
import akka.actor.{Actor, ActorRef, Props}
class A(refToB: ActorRef) extends Actor { ... }
object A {
def props(refToB: ActorRef): Props = Props(new A(refToB))
}
There are alternative ways you can pass the reference to actor B to actor A, but using the constructor is arguably the easiest choice. In the example above, we also provide a method for creating the correct Props for the actor.
Now that you can control the reference to actor B, you can replace the actor reference with test probe in tests.
import akka.testkit.TestProbe
// Initialise a test probe
val probe = TestProbe()
// Actor A with reference to actor B replaced with the test probe
val a = system.actorOf(A.props(probe.ref))
// Send a message to actor A
a ! someMessage
// Verify that the probe received a correct response from actor A
p.expectMsgType[MsgToB]
Notice that I created the actor using the actor system from the TestKit instead of using the TestActorRef. This means that the actor message processing will be asynchronous instead of synchronous. Personally, I've found the asynchronous testing style to be a better fit because it better represents how the actor is run in a production system. Asynchronous testing is also recommended in the official documentation.
I have 2 actors :
class ActorA extends Actor {
def receive = ???
}
object ActorA {
val actorA = system.actorOf(Props[ActorA])
}
class ActorB extends Actor {
def receive = {
case aMessage => ActorA.actorA ! aMessage
}
}
I want the actorA to have at any time only one instance (to apply a kind of back pressure)
But with the code above, if there's an error in the ActorA actor, the actor is restarted and the ActorRef actorA is no longer correct.
What's the correct pattern to use in this case ? Must I use ActorSelection ?
Yes. .actorOf() creates an actor
Assuming your two actors are created once in an init Class/Object/Main
val actorA = system.actorOf(Props[ActorA])
val actorB = system.actorOf(Props[ActorB])
Recover the reference to the existing ActorA from the context
class ActorB extends Actor {
val aA = context.actorSelection( "/user/ActorA" )
def receive = {
case aMessage => aA ! aMessage
}
}
Alternatives are
pass ActorA ActorPath or its reference to the constructor of ActorB
create ActorA as a child of ActorB (if that makes sense in your case)
Basically it seems you want a singleton in a distributed system.
Firstly I'd like to highlight that this can get you in trouble if you don't handle partitions very well. Secondly, if you're only on 1 node, than that's not a problem. And lastly, this is implemented as Akka's built-in cluster-singleton, so you can give it a look.
I am learning akka-remote and one of the things I do in my LocalActorSystem is getting remote actor reference and send messages to him
class LocalActor extends Actor {
val remote = context.actorSelection("akka.tcp://HelloRemoteSystem#127.0.0.1:5150/user/RemoteActor")
var counter = 0
def receive = {
case "START" =>
remote ! "Hello from the LocalActor"
case msg: String =>
println(s"LocalActor received message: '$msg'")
if (counter < 5) {
sender ! "Hello back to you"
counter += 1
}
}
}
My Remote looks like
object Remote extends App {
val system = ActorSystem("HelloRemoteSystem", ConfigFactory.load("remote"))
val remoteActor = system.actorOf(Props[RemoteActor], name = "RemoteActor")
remoteActor ! "The RemoteActor is alive"
}
class RemoteActor extends Actor {
def receive = {
case msg: String =>
println(s"RemoteActor received message '$msg'")
sender ! "Hello from the RemoteActor"
}
}
I also wanted to watch remoteActor so that if its dead, LocalActorSystem get to know. So I did
val remote = context.actorSelection("akka.tcp://HelloRemoteSystem#127.0.0.1:5150/user/RemoteActor")
context watch remote
but then compiler fails with following message
Question
How come I am able to send message to ActorSelection since it is not Actor?
How can I watch RemoteActor?
Update
However, the deprecated API does not complain
val remote = context.actorFor("akka.tcp://HelloRemoteSystem#127.0.0.1:5150/user/RemoteActor")
context watch remote
When you do a lookup via actorSelection, that type of object you get back is an ActorSelection and not an ActorRef. Now, an ActorSelection does support both tell (!) and ask (?) so you can interact with it the same way you would an ActorRef. But an looking up actors via actorSelection supports the concept of a wild card, so the ActorSelection you get back potentially represents more than one actor and would allow you to send messages to more than one actor. For instance, if you did :
system.actorSelection("/user/foo/*")
this would give you an ActorSelection for all children under the parent ActorRef bound to the name foo. If there were two children and you send a message via that ActorSelection, that message would be delivered to both children.
In your case, it looks like you are looking up a single actor instance. In that case, you can get an ActorRef from your ActorSelection by calling resolveOne on it. This will return a Future[ActorRef] that when completed will provide you with an ActorRef that you can watch remotely. You could also send the ActorSelection an Identify message and wait for the ActorIdentity response containing the ref to watch.
You should check out the docs here, specifically the Identifying Actors via Actor Selection section.
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.