What does Akka's Inbox.create(actorsystem) actually do? Will it create a new mailbox for all the actors as we have created the inbox on the system? And what does inbox.watch(actorref) do?
Can you explain what inbox.send and inbox.receive actually do?
From the source code for Inbox:
/**
* An Inbox is an actor-like object which is interrogated from the outside.
* It contains an actor whose reference can be passed to other actors as
* usual and it can watch other actors’ lifecycle.
*/
The Inbox object is a way to communicate with an actor from outside an actor. Let's say we wanted to send messages to and receive replies from an actor named myActor, and we wanted to do this from outside an actor. (The below code samples are adapted from the documentation.)
// this code is not inside an actor
ActorRef myActor = ???
final Inbox inbox = Inbox.create(system);
inbox.send(myActor, "ping");
Inbox.create(system) creates a system-level actor under the covers. inbox.send(myActor, "ping"); sends the message "ping" to myActor with Inbox's internal actor as the sender. Because the Inbox's actor is the sender, it can get a reply from myActor with inbox.receive:
try {
assert inbox.receive(Duration.create(1, TimeUnit.SECONDS)).equals("pong");
} catch (java.util.concurrent.TimeoutException e) {
// timeout
}
inbox.watch registers the Inbox's actor to be notified via DeathWatch when myActor has been terminated:
inbox.watch(myActor);
myActor.tell(PoisonPill.getInstance(), ActorRef.noSender());
try {
assert inbox.receive(Duration.create(1, TimeUnit.SECONDS)) instanceof Terminated;
} catch (java.util.concurrent.TimeoutException e) {
// timeout
}
Inbox.create(system) does not create a new mailbox for all the actors in a system. Don't let the word "inbox" confuse you. Also, Akka enables by default a dispatcher that creates one mailbox per actor; the Inbox object doesn't change that.
Related
I have an Actor and when it recieves a StartMessage, it should change state using Become(Started). How do I unit test whether or not the Actor's state has changed to Started() ?
MyActor class
public class MyActor : ReceiveActor
{
public MyActor()
{
Receive<StartMessage>(s => {
Become(Started); // This is what I want to unit test
});
}
private void Started()
{
Console.WriteLine("Woo hoo! I'm started!");
}
}
Unit Test
[TestMethod]
public void My_actor_changes_state_to_started()
{
// Arrange
var actor = ActorOfAsTestActorRef<MyActor>(Props.Create(() => new MyActor()));
// Act
actor.Tell(new StartMessage());
// Assert
var actorsCurrentState = actor.UnderlyingActor.STATE; // <-- This doesn't work
Assert.AreEqual(Started, actorsCurrentState);
}
UPDATE
Related to the answer from tomliversidge: My reason for writing this unit test was academic but in reality, it's not a good unit test which is why you aren't able to do it as I'd hoped. From Petabridge's Unit Testing Guide:
In reality, if one actor wants to know the internal state of another actor then it must send that actor a message. I recommend you follow the same pattern in your tests and don’t abuse the TestActorRef. Stick to the messaging model in your tests that you actually use in your application.
You would normal test this by message passing. For example, what messages do you process in the Started state? I'm presuming your example has been simplified to the Console.WriteLine action inside of Started.
If you send the StartMessage and then a second message that is processed when in the Started state you can then assert on a response to this second message.
As a simple suggestion:
private void Started()
{
Receive<StartMessage>(msg => {
Sender.Tell(new AlreadyStarted());
}
}
if StartMessage is received whilst in the Started state, you can then assert on receiving an AlreadyStarted message.
For more info check out the Petabridge article https://petabridge.com/blog/how-to-unit-test-akkadotnet-actors-akka-testkit/
I have an actor which is orchestrating database updates. I need to ensure that each operation gets executed only after the previous one gets completed.
This because operation B will reuse the result of operation A.
Here the code I wrote for the actor.
class DbUpdateActor(databaseOperations: DBProvider) extends Actor {
implicit val ec:ExecutionContext = context.system.dispatcher
def receive: Receive = {
case newInfo : UpdateDb =>
val future = Future {
// gets the current situation from DB
val status = databaseOperations.getSituation()
// do db update
databaseOperations.save(something)
}
future onComplete {
case Success(result: List[Int]) =>
//
case Failure(err: Throwable) =>
//
}
}
}
The code works fine for a single operation. If I fire two updates then the second one is executed asynchronously so it gets started before the first one has completed.
I was reading about different types of mailbox, not sure if having a different one would help.
Any suggestion?
One option you can explore would be to remove that Future and allow that blocking db code to be run within the actor. Then, use a separate dispatcher (perhaps a PinnedDispatcher) to fire-wall this blocking code off from the main actor system's dispatcher, giving it its own thread to run on. By blocking in the body and removing that Future, you will ensure proper sequential execution of the actor's mailbox. A rough sketch of the changes to make that work are as follows:
object DbUpdateActor{
def props(databaseOperations:DBProvider) =
Props(classOf[DbUpdateActor], databaseOperations).
withDispatcher("db-update-dispatcher")
}
class DbUpdateActor(databaseOperations: DBProvider) extends Actor {
def receive: Receive = {
case newInfo : UpdateDb =>
val status = databaseOperations.getSituation()
databaseOperations.save(something)
}
}
Then, as long as you had the following dispatcher configured in your actor system config:
db-update-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}
And you started up the db update actor like so:
val updater = system.actorOf(DbUpdateActor.props(databaseOperations))
Then you should be all set setting this actor up to run that blocking code in a way that won't negatively affect the throughput of the main dispatcher.
How about this: start operation A in a child; when the child is complete it sends the parent a message saying it completed. Then you can start operation B, either in the existing or a new child.
From: https://www.chrisstucchio.com/blog/2013/actors_vs_futures.html
suggests that this is safe:
class FooCounter extends Actor {
var count: Long = 0
def receive = {
case Foo => { count += 1}
case FooCountRequest => { sender ! count }
}
}
Isn't it possible that there will be multiple simultaneous calls to receive, making the value of count uncertain.
My understanding is that the only way this could ever be safe would be if the receive call on this object was made mutex with itself.
The receive method is never called simultaneously by multiple threads. Messages residing in an Actor's mailbox are processed one-at-a-time by the receive method. Multiple other Actors, or functions outside of the ActorSystem, can concurrently enqueue messages to the Actor's mailbox but the ActorSystem eventually orders the messages. From the docs:
Enqueuing happens in the time-order of send operations, which means
that messages sent from different actors may not have a defined order
at runtime due to the apparent randomness of distributing actors
across threads.
The receive method's serial processing is guaranteed by the fact that you never actually get an Actor value (which has a receive) from the ActorSystem. Rather, you only get an ActorRef which does not have receive method:
val actorSystem = akka.actor.ActorSystem()
//not an Actor but an ActorRef
val actorRef : ActorRef = actorSystem actorOf Props[FooCounter]
actorRef.receive(Foo) //COMPILE TIME ERROR!
The only way to "invoke" the receive method is to send a message to the ActorRef:
actorRef ! Foo //non-blocking, enqueues a Foo object in the mailbox
Relating back to your question: the ActorSystem acts as a pseudo-mutex for all Actor instances.
Therefore, the code in your example is absolutely safe and the state will only be accessed by one message at any given time.
Totally agree with Ramon. You can think of it have a mail box outside your house(Actor) and mail are coming to your mail box though your address (ActorRef) and you only have 1 single person at your home to take care your mail one at a time.
Besides, for more functional style and maintain immutability of code. I would do the following instead:
class FooCounter extends Actor {
def _receive(count: Long): Receive = {
case Foo =>
context.become(_receive(count + 1))
case FooCountRequest =>
sender() ! count
}
def receive = _receive(0L)
}
For this simple example, there are no difference between mine and yours. But when system become more complex, my code are less error prone.
I have a Scala unit test for an Akka actor. The actor is designed to poll a remote system and update a local cache. Part of the actor's design is that it doesn't attempt to poll while it's still processing or awaiting the result of the last poll, to avoid flooding the remote system when it experiences a slowdown.
I have a test case (shown below) which uses Mockito to simulate a slow network call, and checks that when the actor is told to update, it won't make another network call until the current one is complete. It checks the actor has not made another call by verifying a lack of interactions with the remote service.
I want to eliminate the call to Thread.sleep. I want to test the functionality of the actor without relying on waiting for a hardcoded time, in every test run, which is brittle, and wastes time. The test can poll or block, waiting for a condition, with a timeout. This will be more robust, and will not waste time when the test is passing. I also have the added constraint that I want to keep the state used to prevent extra polling var allowPoll limited in scope, to the internals of the PollingActor.
is there a way force a wait until the actor is finished messaging itself? If there's a way I can wait until then before trying to assert.
is it necessary to send the internal message at all? Couldn't I maintain the internal state with a threadsafe datastructure, such as java.util.concurrent.AtomicBoolean. I have done this and the code appears to work, but I'm not knowledgeable enough about Akka to know if it's discouraged -- a colleague recommended the self message style.
is there better, out-of-the-box functionality with the same semantics? Then I would opt for an integration test instead of a unit test, though I'm not sure if it would solve this problem.
The current actor looks something like this:
class PollingActor(val remoteService: RemoteServiceThingy) extends ActWhenActiveActor {
private var allowPoll: Boolean = true
def receive = {
case PreventFurtherPolling => {
allowPoll = false
}
case AllowFurtherPolling => {
allowPoll = true
}
case UpdateLocalCache => {
if (allowPoll) {
self ! PreventFurtherPolling
remoteService.makeNetworkCall.onComplete {
result => {
self ! AllowFurtherPolling
// process result
}
}
}
}
}
}
trait RemoteServiceThingy {
def makeNetworkCall: Future[String]
}
private case object PreventFurtherPolling
private case object AllowFurtherPolling
case object UpdateLocalCache
And the unit test, in specs2, looks like this:
"when request has finished a new requests can be made" ! {
val remoteService = mock[RemoteServiceThingy]
val actor = TestActorRef(new PollingActor(remoteService))
val slowRequest = new DefaultPromise[String]()
remoteService.makeNetworkCall returns slowRequest
actor.receive(UpdateLocalCache)
actor.receive(UpdateLocalCache)
slowRequest.complete(Left(new Exception))
// Although the test calls the actor synchronously, the actor calls *itself* asynchronously, so we must wait.
Thread.sleep(1000)
actor.receive(UpdateLocalCache)
there was two(remoteService).makeNetworkCall
}
The way we have chosen to solve this for now is to inject the equivalent of an observer into the actor (piggybacking on an existing logger which wasn't included in the listing in the question). The actor can then tell the observer when it has transitioned from various states. In the test code we perform an action then wait for the relevant notification from the actor, before continuing and making assertions.
In the test we have something like this:
actor.receive(UpdateLocalCache)
observer.doActionThenWaitForEvent(
{ actor.receive(UpdateLocalCache) }, // run this action
"IgnoredUpdateLocalCache" // then wait for the actor to emit an event
}
// assert on number of calls to remote service
I don't know if there's a more idiomatic way, this seems like a reasonable suggestion to me.
Let's say I have an actor like this (Using Akka 2.1 with Scala 2.10):
class ClientActor extends Actor with ActorLogging {
val configurationManager = context.actorOf(Props[ConfigurationManager], "ConfigurationManager")
def disconnected: Receive = {
case msg: Connect =>
configurationManager ! msg
context.become(connecting)
}
..
def recieve = disconnected
}
So now when the Client receives a Connect message, it sends it to the ConfigurationManager and also goes into a different state. That's fine, but now I want to test this.
val clientRef = TestActorRef(new ClientActor).
clientRef ! new Connect
// ??
I can't expectMsg() or so here since it will be sent to a different actor. What is the best practice to handle such a situation? I just want to make sure that the message gets sent, but I dont know how to do this.
Thanks,
Michael
Pass the dependency in as a constructor parameter:
Normal code:
val configActor =
system.actorOf(Props[ConfigurationManager], "configManager")
val clientActor =
system.actorOf(Props(new ClientActor(configActor)), "clientActor")
Test code:
val clientActor =
system.actorOf(Props(new ClientActor(testActor)), "clientActor")
Perhaps you should just trust that the message sending mechanisms inside Akka, work as advertised. If you really, really can't trust this, then the best solution is to download the Akka source code and either add your own unit tests to cover your use cases, or modify the code to support your own unit testing needs.
Or you could use something like Camel to do all the message sending and intercept messages that way.
If you abstract out the creation of the collaborating actor, then you can inject a test actor that does whatever you want. The situation is very similar to testing collaboration between ordinary objects.