We're migrating our project to typed akka Actors. We have services that can create actors at will, something like:
class Service(ac: ActorContext[_])
def action() = {
ac.spawn(MyBehavior().receive)
}
}
The problem arises when we're trying to test this service. It seems that we should only use testKit.spawn or testKit.createTestProbe methods. It works fine for unit-testing our classes.
But there is no way to get ActorContext[_] to pass it to services that are being tested.
So, it seems that that we are misusing the ActorContext in our service. But how a service can create a new actor?
I have an idea of passing a special ActorRef[CreateActor] that can create those actor. This way we can remove the dependency on ActorContext[_] in the Service, but I wanted to see if there is a better option.
First of all, you should not be passing ActorContext around, as many of the methods exposed in context are not thread safe.
You can create single ActorSystem[SpawnProtocol.Command] per JVM and pass around that to your services.
Then you can send Spawn command which takes typed actor behavior to injected actorSystem.
val echoActor: Future[ActorRef[Echo]] = actorSustem ? { replyTo: ActorRef[ActorRef[Echo]] => Spawn(echoBehavior, "echo-actor", Props.empty, replyTo)}
Do you really need to create actors from the service though?
Maybe you can have top level wiring where you create all the necessary actors and then inject ActorRef to your services.
Off-course if your actors are short lived and gets created and destroyed based on the demand, then what I suggested above makes sense.
Related
Disclaimer: I have no scala experience for now, so my question is connected with very basics.
Consider the following example (it may be incomplete):
import akka.actor.{ActorSystem, Props}
import akka.io.IO
import spray.can.Http
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import akka.actor.Actor
import spray.routing._
import spray.http._
object Boot extends App {
implicit val system = ActorSystem("my-actor-system")
val service = system.actorOf(Props[MyActor], "my")
implicit val timeout = Timeout(5.seconds)
IO(Http) ? Http.Bind(service, interface = "localhost", port = 8080)
}
class MyActor extends Actor with MyService {
def actorRefFactory = context
def receive = runRoute(myRoute)
}
trait MyService extends HttpService {
val myRoute =
path("my") {
post {
complete {
"PONG"
}
}
}
}
My question is: what actually happens when control reaches complete block? The question seems to be too general, so let me split it.
I see creation of a single actor in the example. Does it mean that the application is single-threaded and uses only one cpu core?
What happens if I do blocking call inside complete?
If p. 1 is true and p. 2 will block, how do I dispatch requests to utilize all cpus? I see two ways: actor per request and actor per connection. The second one seems to be reasonable, but I cannot find the way to do it using spray library.
If the previous question is irrelevant, will detach directive do? And what about passing function returning Future to complete directive? What is the difference between detach and passing function returning the Future?
What is the proper way to configure number of working threads and balance requests/connections?
It would be great if you point me explanations in the official documentation. It is very extensive and I believe I am missing something.
Thank you.
It's answered here by Mathias - one of the Spray authors. Copying his reply for the reference:
In the end the only thing that really completes the request is a call
to requestContext.complete. Thereby it doesn't matter which thread
or Actor context this call is made from. All that matters is that it
does happen within the configured "request-timeout" period. You can of
course issue this call yourself in some way or another, but spray
gives you a number of pre-defined constructs that maybe fit your
architecture better than passing the actual RequestContext around.
Mainly these are:
The complete directive, which simply provides some sugar on top of the "raw" ctx => ctx.complete(…) function literal.
The Future Marshaller, which calls ctx.complete from an future.onComplete handler.
The produce directive, which extracts a function T => Unit that can later be used to complete the request with an instance of a custom
type.
Architecturally, in most cases, it's a good idea to not have the API
layer "leak into" the core of your application. I.e. the application
should not know anything about the API layer or HTTP. It should only
deal with objects of its own domain model. Therefore passing the
RequestContext directly to the application core is mostly not the best
solution.
Resorting to the "ask" and relying on the Future Marshaller is an
obvious, well understood and rather easy alternative. It comes with
the (small) drawback that an ask comes with a mandatory timeout check
itself which logically isn't required (since the spray-can layer
already takes care of request timeouts). The timeout on the ask is
required for technical reasons (so the underlying PromiseActorRef can
be cleaned up if the expected reply never comes).
Another alternative to passing the RequestContext around is the
produce directive (e.g. produce(instanceOf[Foo]) { completer =>
…). It extracts a function that you can pass on to the application
core. When your core logic calls complete(foo) the completion logic
is run and the request completed. Thereby the application core remains
decoupled from the API layer and the overhead is minimal. The
drawbacks of this approach are twofold: first the completer function
is not serializable, so you cannot use this approach across JVM
boundaries. And secondly the completion logic is now running directly
in an actor context of the application core, which might change
runtime behavior in unwanted ways if the Marshaller[Foo] has to do
non-trivial tasks.
A third alternative is to spawn a per-request actor in the API layer
and have it handle the response coming back from the application core.
Then you do not have to use an ask. Still, you end up with the same
problem that the PromiseActorRef underlying an ask has: how to clean
up if no response ever comes back from the application core? With a
re-request actor you have full freedom to implement a solution for
this question. However, if you decide to rely on a timeout (e.g. via
context.setReceiveTimeout) the benefits over an "ask" might be
non-existent.
Which of the described solutions best fits you architecture you need
to decide yourself. However, as I hopefully was able to show, you do
have a couple of alternatives to choose from.
To answer some of your specific questions: There is only a single actor/handler that services the route thus if you make it block Spray will block. This means you want to either complete the route immediately or dispatch work using either of the 3 options above.
There are many examples on the web for these 3 options. The easiest is to wrap your code in a Future. Check also "actor per request" option/example. In the end your architecture will define the most appropriate way to go.
Finally, Spray runs on top of Akka, so all Akka configuration still applies. See HOCON reference.conf and application.conf for Actor threading settings.
I have a Scala class ComponentBuilder which deals with creating actors and initializing them. It has a field system corresponding to the ActorSystem (among other things).
Now, I'd like to test it using TestKit - intercept logs which actors produce and check them. If I try to use regular EventFilter I can see the log which my actors produce in stdout, but the EventFilter doesn't catch them, I guess because they are in a different ActorSystem.
One solution I thought of was to make ComponentBuilder a subclass of ActorSystem and pass all the AS-commands to its field. I didn't manage to do it, due to protected methods that return InternalActorRef, but anyway I'm not sure if it'll work then, as there will be 2 actor systems anyway.
I also tried to pass some messages from testing class to the actor and wait and check the results. This results in replying to the deadLetters, probably for the same reason - the inner ActorSystem doesn't know about the outer one.
I will appreciate any solution you may have.
I am a little confused by how I am supposed to get a reference to my Actor once it has been crerated in the Akka system. Say I have the following:
class MyActor(val x: Int) extends Actor {
def receive = {
case Msg => doSth()
}
}
And at some stage I would create the actor as follows:
val actorRef = system.actorOf(Props(new MyActor(2), name = "Some actor")
But when I need to refer to the MyActor object I cannot see any way to get it from the actor ref?
Thanks
Des
I'm adding my comment as an answer since it seems to be viewed as something worth putting in as an answer.
Not being able to directly access the actor is the whole idea behind actor systems. You are not supposed to be able to get at the underlying actor class instance. The actor ref is a lightweight proxy to your actor class instance. Allowing people to directly access the actor instance could lead down the path of mutable data issues/concurrent state update issues and that's a bad path to go down. By forcing you to go through the ref (and thus the mailbox), state and data will always be safe as only one message is processed at a time.
I think cmbaxter has a good answer, but I want to make it just a bit more clear. The ActorRef is your friend for the following reasons:
You cannot ever access the underlying actor. Actors receive their thread of execution from the Dispatcher given to them when they are created. They operate on one mailbox message at a time, so you never have to worry about concurrency inside of the actor unless YOU introduce it (by handling a message asynchronously with a Future or another Actor instance via delegation, for example). If someone had access to the underlying class behind the ActorRef, they could easily call into the actor via a method using another thread, thus negating the point of using the Actor to avoid concurrency in the first place.
ActorRefs provide Location Transparency. By this, I mean that the Actor instance could exist locally on the same JVM and machine as the actor from which you would like to send it a message, or it could exist on a different JVM, on a different box, in a different data center. You don't know, you don't care, and your code is not littered with the details of HOW the message will be sent to that actor, thus making it more declarative (focused on the what you want to do business-wise, not how it will be done). When you start using Remoting or Clusters, this will prove very valuable.
ActorRefs mask the instance of the actor behind it when failure occurs, as well. With the old Scala Actors, you had no such proxy and when an actor "died" (threw an Exception) that resulted in a new instance of the Actor type being created in its place. You then had to propagate that new instance reference to anyone who needed it. With ActorRef, you don't care that the Actor has been reincarnated - it's all transparent.
There is one way to get access to the underlying actor when you want to do testing, using TestActorRef.underlyingActor. This way, you can write unit tests against functionality written in methods inside the actor. Useful for checking basic business logic without worrying about Akka dynamics.
Hope that helps.
I'm building up an actor hierarchy in which some actors reply to messages they get directly to a well-known actor (fixed name). I.e. these actors (far-removed in the hierarchy) obtain an actorRef via context.actorFor("akka://...").
I.e. for example, I have an "orchestrating" actor:
system.actorOf(Props[OrchestratingActor], name = "orchestrator")
which will then have an address of the kind akka://application/user/orchestrator
and someplace else, a random worker that received a message and wants to talk to the orchestrator:
class RandomWorker extends Actor {
def theOrchestrator = context.actorFor("akka://application/user/orchestrator")
def receive = {
case Foo =>
theOrchestrator ! "Bar"
}
}
Now, I'd like to test those actors and am wondering about how to deal with those addresses: when unit-testing an actor (e.g. using TestActorRef), how do I go about checking what's being sent to the remote address? One idea would be to (when possible) provide the address to the well-known actor via the constructor, and pass in the address of a TestActor to see what's being received. However I wonder if there isn't a way to "impersonate" a given address in the test, esp. in situation where the addresses aren't simple.
In other words I'd like to test the behavior of the actor (will it indeed have sent "Bar" to the orchestrator upon receiving a Foo
My recommendation would be to avoid using look-ups of actors for the purpose you show. It is rather a tool for the setup phase of your application, when wiring it all together. But even then most actors’ supervisors will know the dependencies of their children without using look-ups.
Within a local actor system all ActorRefs can be injected top to bottom (using constructor arguments or introduction messages). Look-ups are most useful when introducing remote systems with each other.
There is nothing wrong with injecting the address via the constructor. Let it me know if you need any details, because at the moment I don't know how to make this more clear, since you basically answered your own question. And btw, I don't know, which Akka version you are using, but actorFor has been recently deprecated in favor of ActorSelection, and there are good reasons for this.
So this question is related to an old one of mine: Do I need to re-use the same Akka ActorSystem or can I just create one every time I need one?
I asked a question about the lifecycle of actors, and I knew something was wrong in my mind, but couldn't phrase it correctly. Hopefully I can now :-).
Here's the situation. I want to test actors that have dependencies to other components and actors, so I went about composing my actors in bootstrap time (I'm using scalatra but however you bootstrap your app). I therefore have something like this:
trait DependencyComponent
{
val dependency : Dependency
}
trait ActorComponentA extends Actor with DependencyComponent {
val actorB : ActorRef
}
trait ActorComponentB extends Actor with DependencyComponent
Ok, so now I can test my actors by extending the traits and providing mock dependencies, all good. And I can bootstrap my app like so:
Bootstrap
val system = ActorSystem()
val actorA = system.actorOf(Props[DefaultActorA])
class DefaultActorB extends ActorComponentB {
val dependency = new RealDependency()
}
class DefaultActorA extends ActorComponentA {
val dependency = new RealDependency()
val actorB = context.actorOf(Props[DefaultActorB]).withRouter(RoundRobinRouter(nrOfInstances = 100)))
}
Cool, Im happy :-), now I can use the actorSystem and actorA within my app, and it has a 100 actorB routed to pass work to. So when actorA decideds that the work is done, it's my understanding that it should broadcast to the routed actors to shutdown. At this point when another request comes in actorA can no longer send messages to the router because all its actors are dead.
If I wasn't setting this up at boot time then actorA and its dependencies could be created when needed in my app. But that is very much like "newing up on object" in DI world. In order to test I would end up overriding the places where the actors were created.
Scalatra docs are suggesting creating my actors at boot time, so I feel that I am missing somehting here. Any help appreciated.
Cheers, Chris.
EDIT
I've +1 both #futurechimp and #cmbaxter as these both seem valid but slightly conflicting. So this is an open comment to both of you.
So #cmbaxter am I right in thinking that your suggesting never calling 'stop' on the routed actors and just maintaining a pool of them for use by ALL requests. And #futurechimp, your suggesting having the servlet instantiate the actors per request and killing them at the end of there lifecycle. Right?
It seems like per-request will spawn more actors (but dispose of them). Where the poll will have only a limited set for all requests in which case is there a potential bottle neck to this approach?
I guess basically, I'm asking if my assumptions are correct and if so what are the advantage and disadvantages to both approaches?
Instantiating an ActorSystem is expensive - however instantiating an Actor isn't. If you only want to instantiate your ActorSystem in ScalatraBootstrap, and your Actors elsewhere, that should work fine if that's what you need to do. I'll talk to some other people to confirm this, and then change the docs in Scalatra's Akka Guide to avoid confusion in future.
One of the questions you have to ask yourself here is: Are my actors going to be stateful or stateless. If stateless (and I would prefer this approach personally when possible), then they can be "long-lived" and you can start them when the server boots up and leave them running for the duration of the server's life. When you need to talk to them from elsewhere in the code, use system.actorFor(String) or system.actorSelection(String) (depending on what version of akka you are using) to look up the actor and send it a message. If the actors are going to be stateful, then they probably should be "short-lived" and started up in response to an individual request. In this case, you will not start them up when the server boots up; you will only start up the ActorSystem itself. Then, when the request comes in, you will instantiate via system.actorOf instead and make sure that when the work is done that you stop ActorA as it's the supervisor of all the ActorBs and stopping A will stop all of the Bs started by A.